stackpanel visibility editing in silverlight - asp.net

I am working on silverlight web application (RIA) hosted on to a silverlight web application.
Background: I have a stackpanel in one of the xaml pages. I tried to simplify my problem. It is down as follows:
My xaml page has a stack panel and that stackpanel has only textblock and button in it. only authorized users can see the value in the textblock, when navigated to the xaml page. If the user is unauthorized, I am planning to show "unauthorised" message (instead of value) in the textblock (button is also collapsed. I dont show button.)
FYI, this value of texblock comes from a WCF service and i have made proper attributes for authorization in the service. If unauthorized, value will not come to textblock from service. What I am doing now, is just for UI, when some user tries to enter the url of the page from browser's address bar I want to show him the unauthorised message.
What have I done so far:: I gave a name to stackpanel. I gave a name to textblock and a name to button. if authorized, I am setting the text value of text block to the service returned value.
If unauthorized, I am changing the visibility and text from .cs file as this.
textblock.Text="unauthorized";
buttonname.Visibility = Visibility.Collapsed;
Problem: Problem is I got an idea. :( When I have a name for my stackpanel, I can say
stackpanelname.Visibility = Visibility.Collapsed;
But I cannot show my message (Textblock) now, coz child controls are also collapsed with parent. Is there any way that, I can collapse my stackpanel (parent control), but only one control of it (one child control, or few) is visible.
Solutions: As I am typing this, I got a solution, I can go for a new stack panel, with a text block, whose visibility I can set to VISIBLE and text as my message. But, is it the only way.? How do we handle these situations?
In general, presuming my question is clear, what is general approach to provide security in this kind of scenarios, from UI. Is it gonna be redirecting to error page/login page or a message to user on the same page or any other thing. Presuming, Backend services, will be having attributes and logic for authorizations.

Normally I would solve such an issue with bindings. I'm not sure if you're willing to take that approach, but given that you are. For example, i would do this:
<TextBlock Text="{Binding AuthorizationCaption,FallbackValue='Unauthorized'" />
The fallback value here is used to see what it looks like for design purposes. FallbackValues only get presented when a binding fails.
For the button, I would do this:
<Button Content="My Button" Visibility="{Binding IsAuthorized,Converter={StaticResource VisibilityValueConverter},FallbackValue=Collapsed}" />
In the above example, you will notice that I used what I called a VisibilityValueConverter. This of course would be a part of my resources that I define right about "LayoutRoot" in the XAML. e.g.
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/MyUICustomizationLib;component/rdMyResourceDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
My VisibilityValueConverter is a simple converter to convert a boolean value to a visibility attribute. It's pretty reusable. It implements IValueConverter which I think is in System.Windows.Data. Along the lines:
public class TVisibilityValueConverter:IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool _visibility = (bool)value;
return _visibility ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Visibility _visibility = (Visibility)value;
return _visibility == Visibility.Visible;
}
}
I would embed my value converter in my ResourceDictionary by , first, defining a namespace to it's location -
xmlns:muicl="clr-namespace:MyUICustomizationLib.ValueConverters"
Then defining the static resource:
<muicl:TVisibilityValueConverter x:Key="VisibilityValueConverter" />
Last, but not least, Implement my viewmodel properties and commands to fit what has to be. i.e, I make the neccesary server calls, and on the call backs, i toggle the AuthorizationCaption property and the IsAuthorized property accordingly. The smmoothest way would be to let the AuthorizationCaption be a simple if statement that depends on the IsAuthorized property. Let the set method of the IsAuthorizedProperty raise an event notification that the AuthorizationCaption changed too. e.g.
set
{
__fIsAuthorized = value;//set private member
this.RaisePropertyChanged("IsAuthorized");
this.RaisePropertyChanged("AuthorizationCaption");
}
Of course they may be more to set up on your end. But this would be the route I would take.

Related

Adding item to collection does not refresh activity designer

Am re-hosting my designer and have added a toolbox item which has a WorkflowItemsPresenter to render multiple child activity items. So my model item has a collection as:
Sequence _innerSequence = new Sequence();
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[Browsable(false)]
[Description("")]
public Collection<Activity> Activities { get { return _innerSequence.Activities; } }
and the binding is
<sap:WorkflowItemsPresenter Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" Items="{Binding Path=ModelItem.Activities}" VerticalAlignment="Center" HorizontalAlignment="Center" HintText="Drop activities here">
<sap:WorkflowItemsPresenter.SpacerTemplate>
<DataTemplate>
<Label HorizontalAlignment="Center" Height="21"/>
</DataTemplate>
</sap:WorkflowItemsPresenter.SpacerTemplate>
</sap:WorkflowItemsPresenter>
The binding works absolutely fine when the designer is loaded. Now i want to clear and add new items to this collection when some filter is updated on the designer. So in the set accessor of this filter property i call a method which does the following:
private void RefreshApplication()
{
Activities.Clear();
Activities.Add(new AddXYZApplication() { ApplicationName = "Test" });
}
Though the collection gets updated the designer does not refresh. I know there is a way of doing this by writing some designer code-behind (i.e. updating the collection via the model item tree), but I would ideally like to have NO code-behind and expect it work like any other WPF application.
Any help would be greatly appreciated as I have been trying to devise a way (using multi-binding, using eventing etc) from sometime now.
Cheerio,
V
Just to answer after my comment.
When you're editing through WorkflowDesigner you haven't an Activity per se. What you have is a ModelItem.
From the moment you load an activity to the designer, through WorkflowDesigner.Load(activity) you don't have an activity anymore, you just start editing a ModelItem.
You can access XAML through WorkflowDesigner.Text (after flush it) and do whatever you want with it. For example load it into an ActivityBuilder or WorkflowService but that is it.
Designers don't known, and never will, that activities have Collection<Activities>, Collection<Variable> or any other properties. They only know the ModelItem and the properties it has, period.
In resume: changes have to be made to ModelItem because it's what designers bind to.

Pass a variable to user control to determine display

Apologies if this is something really simple.
I've found various C# examples here, but I can't seem to get a VB version working.
I want to be able to pass a simple variable into a User Control to determine whether it shows a certain section of data.
It's basically a Customer Data form, and in some circumstances I need to show a line with the customers account number and sort code, and in some I don't, so my user control:
<controls:customerForm ID='customerForm' showBankDetails="no" runat='server' />
But I can't work out what to do with the showBankDetails variable in Code Behind to stop it from rendering that section, or simply hide it with a CSS snippet.
How do I access that variable in the code behind using VB.NET?
Normally I'd have optional stuff in a asp:panel on the page in the right spot, and in the page load or where ever, do something like:
me.OptionalStuffPanel.Visible = me.ShowBankDetails
ShowBankDetails would need to be defined as a public property of the page class:
private _ShowBankDetails as boolean
Public Property ShowBankDetails() As boolean
Get
Return _ShowBankDetails
End Get
Set(ByVal value As boolean)
_ShowBankDetails = value
End Set
End Property
If you want the property to appear in the property grid here is an article to show you how!
http://www.codeproject.com/KB/vb/using_propertygrid.aspx

Setting a design-time property from the properties window of a custom web server control hangs/crashes Visual Studio 2010

As my title says, I have a set property crash problem.
Here's the scenario:
I have created a simple custom ASP.Net server control that generates some text.
I wanted to give design-time property for that text so its style can be accessed by developers from the properties window.
All the properties in the properties window are working except the ones with the type System.Web.UI.WebControls.Style that I have created.
Here is my property:
[Bindable(true)]
[Category("Appearance")]
[Description("The style for the header")]
[Localizable(true)]
public Style HeaderTextStyle
{
get
{
Style s = (Style)(ViewState["HeaderTextStyle"] == null ? Styles.defaultHeaderStyle : ViewState["HeaderTextStyle"]);
return s;
}
set
{
ViewState["HeaderTextStyle"] = value;
}
}
Oh and Styles.defaultHeaderStyle is just a property from an internal class that returns a new Style.
Let me point that the hanging/crashing occurs only when I CHANGE the property, so it cannot be from the getter.
I won't paste my render control because the error occurs even when I'm not rendering anything.
What is it that causes this?
Thank you.
I found the answer to my problem.
You see, the Style class is a property that has sub-properties and it is called a complex property. Complex properties ( a property that has subproperties) need custom state management to use view state. The Style class need design-time attributes to enable persistence within the control's tags. So what I wrote in my original post will not work.
For complete explanation visit: Server Control Properties Example from MSDN
I managed to implement it using that example. I hope this will be useful to others out there.

MVVM Light + Blend designer view error: Cannot find resource named 'Locator'.

The application runs fine but i could not see my design in the designer view.
It says Cannot find resource named 'Locator'. Obviously, i did not change anything in the code, i just did the data binding using the data binding dialog...
anyone facing the same problem?
There are two known occurrences where this can happen.
If you change to Blend before you built the application, the DLLs are not available yet and this error can be seen. Building the application solves the issue.
There is a bug in Expression Blend where, if you are placing a user control in another user control (or Window in WPF), and the inner user control uses a global resource, the global resource cannot be found. In that case you will get the error too.
Unfortunately I do not have a workaround for the second point, as it is a Blend bug. I hope we will see a resolution for that soon, but it seems to be still there in Blend 4.
What you can do is
Ignore the error when working on the outer user control. When you work on the inner user control, you should see the design time data fine (not very satisfying I know).
Use the d:DataContext to set the design time data context in Blend temporarily.
Hopefully this helps,
Laurent
I've come up with a reasonably acceptable workaround to this problem since it doesn't appear to have been fixed in Blend 4:
In the constructor for your XAML UserControl just add the resources it needs, provided you're in design mode within Blend. This may be just the Locator, or also Styles and Converters as appropriate.
public partial class OrdersControl : UserControl
{
public OrdersControl()
{
// MUST do this BEFORE InitializeComponent()
if (DesignerProperties.GetIsInDesignMode(this))
{
if (AppDomain.CurrentDomain.BaseDirectory.Contains("Blend 4"))
{
// load styles resources
ResourceDictionary rd = new ResourceDictionary();
rd.Source = new Uri(System.IO.Path.Combine(Environment.CurrentDirectory, "Resources/Styles.xaml"), UriKind.Absolute);
Resources.MergedDictionaries.Add(rd);
// load any other resources this control needs such as Converters
Resources.Add("booleanNOTConverter", new BooleanNOTConverter());
}
}
// initialize component
this.InitializeComponent();
}
There may be some edge cases, but its working OK for me in the simple cases where before I'd get a big red error symbol. I'd LOVE to see suggestions on how to better solve this problem, but this at least allows me to animate user controls that otherwise are appearing as errors.
You could also extract out the creation of resources to App.xaml.cs:
internal static void CreateStaticResourcesForDesigner(Control element)
{
if (AppDomain.CurrentDomain.BaseDirectory.Contains("Blend 4"))
{
// load styles resources
ResourceDictionary rd = new ResourceDictionary();
rd.Source = new Uri(System.IO.Path.Combine(Environment.CurrentDirectory, "Resources/Styles.xaml"), UriKind.Absolute);
element.Resources.MergedDictionaries.Add(rd);
// load any other resources this control needs
element.Resources.Add("booleanNOTConverter", new BooleanNOTConverter());
}
}
and then in the control do this BEFORE InitializeComponent():
// create local resources
if (DesignerProperties.GetIsInDesignMode(this))
{
App.CreateStaticResourcesForDesigner(this);
}
Note: At some point in time this stopped working for me and I ended up hardcoding the path to the Styles.xaml because I got frustrated trying to figure out which directory I was in.
rd.Source = new Uri(#"R:\TFS-PROJECTS\ProjectWPF\Resources\Styles.xaml", UriKind.Absolute);
I'm sure I could find the right path with 5 minutes work, but try this if you're at your wits end like I was!
In MyUserControl.xaml, instead of:
DataContext="{Binding Main, Source={StaticResource Locator}
use:
d:DataContext="{Binding Main, Source={StaticResource Locator}
where "d" has been previously defined as:
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
The reason and workaround explained here
http://blogs.msdn.com/b/unnir/archive/2009/03/31/blend-wpf-and-resource-references.aspx
Look at (b) part of the post.
I had a similar problem with a user control resource.
I added this in my usercontrol xaml code:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/GinaControls;component/Resources/GinaControlsColors.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
Where GinaControls is the namespace where the control class is declared and /Resources/GinaControlsColors.xaml is the project folder and xaml resource file name.
Hope this helps.
Just add this in your App.xaml.cs at the very beginning
here's my piece of code
[STATThread()]
static void main(){
App.Current.Resources.Add("Locator", new yournamespace.ViewModel.ViewModelLocator());
}
public App(){
main();
}
Make sure the Blend has opened the entire solution and NOT just the single project containing the views. I was right-clicking in Visual Studio and selecting Open In Expression Blend. To my surprize, Blend could not find the solution file, so it only opened the single project.
When I realized this, I launched Blend directly, pointed it to the solution file, and then Blend was able to find the ViewModelLocator in my view.

Cannot access custom properties on nested user control

Ok, please understand the architecture here first.
OurMasterPage.aspx has user control Header.ascx
Header.ascx has a user control in it called LandingPageTopNav
LandingPageTopNav.ascx has a public property named "LandingPage" that is there to be able to set by the user using this control.
And I have a Third.aspx page in which I need to set the LandingPageTopNav property to a LandingPage object
The problem is that I can't get this to work in my ThirdPage.aspx.cs:
Master.LandingPageTopNav.LandingPage = this.landingPage;
Master.LandingPageTopNav.Visible = true;
And that is, I can't get the first line to work where I'm trying to reference the LandingPage property. The second line is fine. My Third.aspx definitely can reference my master page objects otherwise from code-behind.
I'd venture to guess that the LandingPageTopNav property of OurMasterPage doesn't return a value typed as LandingPageTopNav. It probably returns the correct control typed as something more generic (e.g. Control); which is why setting the Visible property works but not the LandingPage property.

Resources