Proper way to set MenuItem visibility in Context Menu? - silverlight

I am trying to do things the .net way and declare my menu items for my context menu like a good citizen in xaml :).
I have a listbox that contains a bunch of list items based of ItemsSource.
QUESTION: How can I dynamically set the visibility of a particular menu item based off a function to be defined in the Page class?
I could just data bind this to a property in my DataContext class, but there are a few things that are more ui-specific that it really should not know about, so I'd like to keep it clean.
Can I somehow bind the visibility to a function in the page class and pass it the data context and have it return the appropriate visibility value required? Or is there another way?
Thanks!
swine

Bindings are useful because the UI updates whenever the bound value changes. Since a function doesn't update, even if you could bind to a function, the UI would never change. The UI would also never know when to call the bound function.
Why don't you just bind to a bool DataProperty and then use the function to update the bool. If you explain more of what you are trying to do, then I can give you a more detailed solution.

Related

WPF: How to trigger GUI behaviours in response to view-model events?

I'm developing a WPF/MVVM application and I have a listbox binding to data in a ViewModel. At various points I need the view model to cause the listbox to scroll to a given element.
How can I do this without creating a custom control and while still maintaining good separation of concerns?
I've currently got it working by creating a custom behavior class in the view layer with a dependency property VisibleIndex which the XAML code then binds to an integer in the view model:
<ListBox x:Name="myListBox"
local:ListBoxVisibilityBehavior.VisibleIndex="{Binding VisibleIndex}">
When the integer is set it triggers the dependency properties update handler which tells the listbox to scroll to the associated index.
This seems a bit hacky though because the dependency property value is never changed by the listbox and the update handler only gets called when the value changes, so the only way to ensure that the relevent item is visible is to do something like this:
// view-model code
this.VisibleIndex = -1;
this.VisibleIndex = 10;
The only reason I'm using a behaviour class at the moment is for binding my custom dependency property, is there a way to do something like this with events instead?
Attached properties are somewhat required in your case - as at some point, 'somewhere' you need to call the following method...
ListBox.ScrollIntoView(item)
or
ListBoxItem.BringIntoView();
And for that you need some sort of code behind - and attached properties/behaviors are a nice way of packaging that, w/o impacting your MVVM.
Having said that - if you just need to have your 'selected item' scrolled into view at all times (which is the case most of the time). Then you could use a different attached-property based solution (that again):
mvvm how to make a list view auto scroll to a new Item in a list view
All you have to do then is to set or bind to SelectedItem.
That's a bit 'nicer' if you wish - but the mechanism is the same.
For anyone else interested in the answer to this one of the MS engineers on the WPF forum cleared it up for me. Instead of binding to an event directly you bind to a wrapper object that encapsulates that event. The behaviour can then grab the reference to the wrapper from its DP and do whatever it wants with it i.e. subscribe to the event, trigger it etc.

How do I pass an extra variable to a a datatemplate

I have a DataTemplate(well two data templates) that I want to use as views for some
basic form viewmodels(that that contain a value and and boolean indicating whether I want to use the value).
I want to use the datatemplate(s) several times for separate form items. I think the right way to do this is to set it as the ContentControl's ContentTemplate (in that case it will have the same data context right?) but I also want to pass the label string and since the label string is part of the ui and doesn't change it seems wrong to put it in the viewmodel object. How do I give access of the label string to the DataTemplate instance?
Just like its name, a DataTemplate is used to template the Data... For example, if you have a class called MyItem which has a Name and Value and you want this shown in a specific way, you'll set a datatemplate for Item and use it whenever needed.
In your case, you're speaking about having very similar views, with only a minor change between them. This minor change (if I understood your question correctly) is not something that comes from the model or from the viewmodel but something which is entirely view-oriented (a different title for the page, for instance).
If you plan on using a different viewmodel for every view, and each viewmodel has a different purpose - I don't see a problem with adding a Title property to the VM and bind to that too (Remember, MVVM is a set of guidelines, not rules...)
If you still rather have it separated from the viewmodel, then you can use an Attached Property. Create an Attached Property called TemplateTitle, for instance, and have each contentcontrol in each view change it. The label, of course, will bind to that Attached Property.

.NET WinForm ListBox item displays old value untill reassigned to itself

I populate a ListBox control with my own objects redefining ToString(). The objects are displayed correctly when I just add those objects using listBox1.Add(myObject). However, if I later change something in this object, no changes are displayed in the listbox. Debugging reveals that an object inside listBox1.Items is indeed changed, but it is not reflected on a screen.
Interestingly enough, if I reassign a particular listbox item to itself (sounds a bit weird, doesn't it?), like:
listBox1.Items[0] = listBox1.Items[0]
this line will display a correct value on screen.
What is going on here? Does it have anything to do with threading?
Since you're using ToString of the object to provide the text of the list box item, the ListBox has no idea that the value has changed. What you should do instead is have the object implement INotifyPropertyChanged then expose a public property such as Name or Text and return what you normally would have returned from ToString().
Then set the DisplayMember of the ListBox to the name of the new property.
Make sure you are correctly raising the PropertyChanged event in the object and the ListBox should be able to automatically pick up the changes.
Edit: Adrian's edit reminded me that I do believe you'll need to use a BindingList as your data source in order for the property change notifications to be picked up. A quick scan in Reflector looks like ListBox on its own will not pick up the property changes mentioned above. But INotifyPropertyChanged + BindingList should.
The ToString() value of each item is cached when the listbox is first displayed. If an item in the listbox's Items collection then changes, the listbox does not notice and still uses the cached ToString() values for display. To force the listbox to update, either call RefreshItems() to refresh all items, or call RefreshItem(int) specifying the index of the item to refresh.
From the MSDN docs for RefreshItems():
Refreshes all ListBox items and retrieves new strings for them.
EDIT: It turns out that both of these methods are protected, so cannot be called externally. In trying to find a solution, I came across this SO question that this question is basically a duplicate of.
Have you tried calling Refresh() on the ListBox? I think the problem is that the ListBox does not know your object changed. The reason reassigning the the item works is because the ListBox will repaint itself when the collection changes.
you could invalidate the control, forcing a re-paint... perhaps..

WPF Visibility based upon global variable value

I have a boolean global variable that is set true if an administrator is logged in and wants to amend the content of the lists and comboboxes. As a result, a button is displayed beside each combo to display a dialog box when clicked.
If I was not coding for WPF, I would probably include some sort of code similar to the following in each Window:
If gAdminEditLists=True Then btnUpdateCombo.Visibility=Visible Else btnUpdateCombo.Visibility=Collapsed
In my WPF app, I am using a style for the button that is used throughout the application and I am guessing that the best way forward is to set the Visibility of the button within the style based upon the value of the gAdminEditLists variable.
The only way I can see of doing this is to use some sort of converter within the button style that converts the gAdminEditLists value to visible or collapsed.
I'm not too sure how to proceed with this or whether this is the best approach, so any suggestions would be appreciated.
well your problem is that you're using a global variable isn't it?
if you had a property that implemented notification or a dependency property you would be ok. the closest thing to a global variable is a property on the app ( i assume thats where your global is )
defining dependency properties on app.xaml, however you could just use INotifyPropertyChanged.
binding to properties in app.xaml.cs
enjoy!
Have a look at the BooleanToVisibilityConverter class in the System.Windows.Controls namespace.

WPF: Switch Template based on UserControl Data

Trying to implement what I thought was a simple concept. I have a user control (view) bound to a view model which provides a list of data. I have added toggle buttons to the usercontrol and would like to allow the user to use these toggle buttons to switch out which template is used to show the data. All of the templates used for the data work, and they are very different from one another so it's not just simple changes to a single template. I'd like to get this as much in XAML as possible.
Here's what I have now:
Where the data appears I have <UserControl Template="{StaticResource ListSwitchingControlTemplate}" />
In that control template I have all "sub templates" - really it's just all 3 representations with their visibility set to Collapsed. Then I use a data trigger on that control template to show the currently selected view. This works, but I noticed that all 3 representations get bound - they each act like they are active (and they are I guess).
I'd rather be able to truly switch the template at run time. I tried converting the containing user control to use a ContentTemplate for itself, but that just messes up all of the binding I have elsewhere. If only UserControls could use DataTriggers I'd be ok.
Any suggestions on how to cleanly go about getting this behavior. I have an idea that I'm just missing something simple.
Thanks,
Dave
you could do it via code?
http://www.switchonthecode.com/tutorials/wpf-tutorial-how-to-use-a-datatemplateselector ???
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/4fd42590-8375-46d0-b7bc-6c217df0f0ba/
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/dbbbb5d6-ab03-49a0-9e42-686fd41e0714
One way to do this would be to use a DataTemplateSelector.
Basically, you create a class that inherits from DataTemplateSelector and override its SelectTemplate virtual function. The return value from the function is the DataTemplate you want to use and in that function you have access to the object and its properties, which you can use to decide which template to select.
There is an example on MSDN here:
http://msdn.microsoft.com/en-us/library/system.windows.controls.datatemplateselector.aspx

Resources