I am using the tree view control in my silverlight project. I use data binding for binding my model to the tree. This works perfect.
After adding some features to the tree I ran into two problems:
When I change a property on my Model, the tree does not get updated, even after my onproperty changed get called and also my converter is not called?(I need to hide the item when a specific property changes) (Answered)
How do I hide an Item in the tree? (I use Textbox + image as Item template)
Stack panel is hidden, but empty container remains in tree
DataTemplate:
<common:HierarchicalDataTemplate ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal" Visibility="{Binding IsAvailable, Converter={StaticResource ItemVisibleConverter} ,Mode=TwoWay}" >
<Image Source="{Binding Converter={StaticResource ImageConverter}}"/>
<controls:Label Name="myItem" Content="{Binding Description, Converter={StaticResource ItemConverter} ,Mode=TwoWay}" Foreground="Black"/>
</StackPanel>
</common:HierarchicalDataTemplate>
Converter:
public object Convert(object value, Type targetType, object parameter, ystem.Globalization.CultureInfo culture)
{
return GetVisibility(value);
}
private Visibility GetVisibility(object value)
{
bool IsVisible= (bool)value;
if (IsAvailableForDownload)
{
return Visibility.Visible;
}
else
{
return Visibility.Collapsed;
}
}
Model
public class MyModel: INotifyPropertyChanged
{
public bool IsAvailable
{
get
{
return _IsAvailableForDownload;
}
set
{
_IsAvailableForDownload = value;
onPropertyChanged(this, "IsAvailableForDownload");
}
}
//Code for on property changed event
}
Regards
You probably need to make sure that your model implements INotifyPropertyChanged so that the binding system can do its job.
Could you have a property of type Visibility that your item template binds to, or a bool plus a value converter that returns a Visibility value?
<DataTemplate>
<Grid Visibility="{Binding ThisThingsIsVisible}">
<Button Content="{Binding Blah}" />
</Grid>
</DataTemplate>
I don't know if this is the recommended way or not - could your bound object not expose hidden items in their collections?
Related
I have successfully passed the following Enum to a Combobox using the following:
public enum Color
{
Blue,
Green,
Yellow
}
public Color _color { get; set; }
public Type Colors
{
get { return typeof(Color); }
}
In the view I have the following:
<ComboBox ItemsSource="{Binding Colors, Converter={StaticResource enumConverter}}">
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding }" FontSize="14"/>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
This lets me pic a color in the box. What I want to do is to bind the chosen color to a property that's part of my viewmodel. I am very new to converters so I might be missing something.
You can bind the SelectedItem of the ComboBox to a property in your view model. The type of that property must match the type of the items generated by the enumConverter.
You can bind Combobox's SelectedItem to the property. I rename the Property to SelectedColor in the ViewModel. The PropertyChanged event is raised in the setter, so when you update the property, for example, from another method inside ViewModel, the view is notified and updated with the new value.
private Color _selectedColor;
public Color SelectedColor
{
get { return _selectedColor; }
set
{
_selectedColor = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("SelectedColor"));
}
}
}
And in the XAML
<ComboBox ItemsSource="{Binding Colors, Converter={StaticResource enumConverter}}"
SelectedItem="{Binding SelectedColor}">
...
Thanks for your time reading my thread.
I am using VS2012, WFP, and .net4.5 on Windows 7 64bit
I have a ListView control with xaml in following:
<ListView Name="lvViewerControl"
SelectionMode="Single"
SelectedIndex="{Binding Path=ViewType, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Background="{x:Null}"
BorderBrush="{x:Null}"
Margin="2">
<Label Name="lblView2D"
Width="40"
Height="40"
Margin="3"
Background="#FF595959"
Foreground="White"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center">
<Image Source="/CaptureSetupModule;component/Icons/2D.png" />
</Label>
<Label Name="lblView3D"
Width="40"
Height="40"
Margin="3"
Background="#FF595959"
Foreground="White"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center">
<Image Source="/CaptureSetupModule;component/Icons/3D.png" />
</Label>
<Label Name="lblViewTiles"
Width="40"
Height="40"
Margin="3"
Background="#FF595959"
Foreground="White"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Visibility="{Binding Path=XYCtrlVisible, Mode=TwoWay, Converter={StaticResource boolToVis}}">
<Image Source="/CaptureSetupModule;component/Icons/Tile.png" />
</Label>
</ListView>
Now I want to collapse the third item, lblViewTiles. I tried to combine its Visibility to a bool, then do the bool to visibility conversion, but it did not work. What I mean by not work is that the Visiblity only collapses when the application starts (the application loads the xml to get the Visibility as it starts). Afterwards, not matter how the binding variable (Visiblity) changes, and the value does change to Collapsed, but the lblViewTiles still in the ListView control, no UI change.
Here is how DataContext are binded:
The DataContex of the ListView is binded to CaptureSetupModules class. The ListView is defined in LiveVM class. The action which is the loading of the xml is in MasterView class. So in order to access the Visibility property in CaptureSetupModules, I simply created a CaptureSetupModules object in MasterView class,
In MasterView class
CaptureSetupModules _captureVM = new CaptureSetupModules();
...
LiveVM _liveVM = new LiveVM;
if (ndList.Count > 0)
{
xyBorder.Visibility = ndList[0].Attributes["Visibility"].Value.Equals("Visible") ? Visibility.Visible : Visibility.Collapsed;
tilesControlBorder.Visibility = ndList[0].Attributes["Visibility"].Value.Equals("Visible") ? Visibility.Visible : Visibility.Collapsed;
this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal,
new Action(
delegate()
{
_captureVM.XYCtrlVisible = ndList[0].Attributes["Visibility"].Value.Equals("Visible") ? true:false;
}
)
);
}
And here is my converter:
public sealed class BooleanToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var flag = false;
if (value is bool)
{
flag = (bool)value;
}
else if (value is bool?)
{
var nullable = (bool?)value;
flag = nullable.GetValueOrDefault();
}
if (parameter != null)
{
if (bool.Parse((string)parameter))
{
flag = !flag;
}
}
if (flag)
{
return Visibility.Visible;
}
else
{
return Visibility.Collapsed;
}
}
This code only makes the item collapsed the first time when the application starts , and it loads the visibility from the xml file. Afterwards, not matter how the XYCtrlVisible, the visibility binding, changes, the UI show no response. The item is always there, or not there.
Basically the problem is: the binded variable changes, the xml file changes as well, but the UI does not change, exception for the first time when the application launches as it loads the xml.
It is probably a little messy here, let me know if you need anything else. I am pretty confused myself too. Thanks.
On the property XYCtrlVisible you need to implement INotifyPropertyChanged
That is how the UI is notified of a changed
Why are you binding that two way?
In Silverlight, MVVM I have to create a property window, but I have just a
List<AProperty> object, where AProperty is an abstract class with some child classes.
I want to bind it to a Silverlight control (but to which one?), with some conditions:
some child-properties must be shown as a textbox, some as a checkbox, and some as a combobox. It comes from the dynamic type.
the AProperty class has a PropertyGroup and a Name field. The order must be alphabetic (PropertyGroup > Name)
Any idea or working example?
My code:
public abstract class AProperty {
private String _Name;
private String _Caption;
private String _PropertyGroup;
public String Name {
get { return _Name; }
set { _Name = value; }
}
public String Caption {
get { return _Caption; }
set { _Caption = value; }
}
public String PropertyGroup {
get { return _PropertyGroup; }
set { _PropertyGroup = value; }
}
}
List<AProperty> Properties;
And the xaml:
<ListBox ItemsSource="{Binding ... Properties ...}">
<!-- Here order the items -->
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Width="250"
Text="{Binding Path=Caption}" />
<!-- And here need I a textbox, or a checkbox, or a combobox anyway -->
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I've found value converters just for a control attribute, not for a whole stackpanel content.
You could use a value converter to check what Type the object is and return the correct control type.
Do you have any sample code so I could give a better example?
The ValueConverter Andy mentions should work. Underneath your Textblock have a ContentPresenter, and bind it's Content.
Content={Binding , ConverterParameter={StaticResource NAMEOFCONVERTER}}.
The binding to the property is empty since you already have the object you want as the context. Then just check the type and return the control you want. you may want to make usercontrol's that are just Textblocks, etc. so that you can set the binding there, otherwise you will have to do it in code.
Thanks Jesse and Andy, here is the solution
The converter:
public class PropertyConverter : IValueConverter {
public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
Binding ValueBinding = new Binding() {
Source = value,
Path = new PropertyPath( "Value" ),
Mode = BindingMode.TwoWay
};
Binding EditableBinding = new Binding() {
Source = value,
Path = new PropertyPath( "Editable" ),
Mode = BindingMode.TwoWay
};
if( value is PropertyString ) {
TextBox tb = new TextBox();
tb.SetBinding( TextBox.TextProperty, ValueBinding );
tb.SetBinding( TextBox.IsEnabledProperty, EditableBinding );
return tb;
} else if( value is PropertyBoolean ) {
CheckBox cb = new CheckBox();
cb.SetBinding( CheckBox.IsCheckedProperty, ValueBinding );
cb.SetBinding( CheckBox.IsEnabledProperty, EditableBinding );
return cb;
} ....
return null;
}
public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
throw new NotImplementedException();
}
}
And the xaml code:
...
xmlns:Converters="clr-namespace:MyConverters"
...
<UserControl.Resources>
<Converters:PropertyConverter x:Key="PropertyInput"/>
</UserControl.Resources>
...
<ListBox ItemsSource="{Binding Path=ItemProperties.GeneralProperties}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="180" />
<ColumnDefinition Width="320" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" Grid.Column="0" />
<ContentPresenter Content="{Binding Converter={StaticResource PropertyInput}}" Grid.Column="1" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Two artikel:
http://shawnoster.com/blog/post/Dynamic-Icons-in-the-Silverlight-TreeView.aspx
http://www.silverlightshow.net/items/Silverlight-2-Getting-to-the-ListBoxItems-in-a-ListBox.aspx
I have an ItemsControl with a DataTemplate that has been defined. My ItemsControl definition looks like the following:
<ItemsControl x:Name="myItemsControl" ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<CheckBox x:Name="myCheckBox" Content="{Binding Name}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This is a simplified version of my DataTemplate. Regardless, when a user clicks a button on the page, I want to loop through the items in myItemsControl and determine if the CheckBox element associated with the item is checked.
How do I determine if a CheckBox is checked for a specific item within an ItemsControl?
Thank you!
Add a property to your data class and databind it, then iterate over the collection itself.
public class myDataClass
{
public string Name { get; set;}
public bool IsSomething { get; set; }
}
<CheckBox x:Name="myCheckBox" Content="{Binding Name}" IsChecked="{Binding IsChecked, Mode=TwoWay}" />
You can try something like traditional iteration:
public bool? TestMyCheckbox(string bindingName)
{
foreach (var item in myItemsControl.Items)
{
if (item.GetType() == typeof(CheckBox))
{
var checkbox = (CheckBox)item;
if (checkbox.Content.Equals(bindingName))
{
return (checkbox.IsChecked);
}
}
}
return null;
}
Additionaly (this may better fit your needs) you can look for a list of checkboxes bindings that are checked:
public IEnumerable<object> TestMyCheckboxes(ItemsControl control)
{
return from Control x in control.Items
where x.GetType().Equals(typeof(CheckBox)) && ((CheckBox)x).IsChecked == true
select ((CheckBox)x).Content;
}
I have a radiobutton group:
<TextBlock Height="24" Text="Update Interval (min):"/>
<RadioButton x:Name="radioButtonTimerNone" IsChecked="{Binding UpdateInterval, Converter={StaticResource updateIntervalToCheckedConverter}, Mode=TwoWay}"} Content="None" />
<RadioButton x:Name="radioButtonTimerOne" IsChecked="{Binding UpdateInterval, Converter={StaticResource updateIntervalToCheckedConverter}, Mode=TwoWay}"
Content="1" />
<RadioButton x:Name="radioButtonTimerFive" IsChecked="{Binding UpdateInterval, Converter={StaticResource updateIntervalToCheckedConverter}, Mode=TwoWay}"
Content="5" />
And a property:
public int UpdateInterval {
get { return _updateInterval; }
set { _updateInterval = value;
onPropertyChanged("UpdateInterval");
}
}
How do I bind the radiobuttons to the property, so radioButtonTimerNone is checked when UpdateInterval is 0, radioButtonTimerOne is checked when UpdateInterval is 1, etc.
I have tried to create a converter, but it doesn't identify which rb is being set:
[ValueConversion(typeof(RadioButton), typeof(bool))]
class UpdateIntervalToCheckedConverter : System.Windows.Data.IValueConverter
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
I expected 'value' to be a radiobutton, but it appears to be the value of UpdateInterval.
Thanks for any hints...
If you are using MVVM and are bound to a ViewModel (I would guess that you are), I usually consider my ViewModel to be a big ValueConverter. Why not put that logic into properties for each?
Here's an example of one of them:
public bool Timer5Enabled
{
get { return UpdateInterval == 5; }
}
And then you'd just bind to that:
<RadioButton
x:Name="radioButtonTimerOne"
IsChecked="{Binding Timer5Enabled, Mode=OneWay}"
Content="1" />
The only thing you'd need to change would be to tie your interval update logic to raise OnChanged for your dependent properties:
public int UpdateInterval {
get { return _updateInterval; }
set { _updateInterval = value;
onPropertyChanged("UpdateInterval");
onPropertyChanged("Timer5Enabled");
onPropertyChanged("...");
}
}
ValueConverters are good to avoid if you can.
Your value converter doesn't get told which RadioButton changed the value - all the binding knows is that the "IsChecked" property was changed, so the new value for IsChecked is the only thing it can tell the converter.
The first thing that springs to my mind is to supply a converter parameter with each of your bindings:
<RadioButton
x:Name="radioButtonTimerNone"
IsChecked="{Binding UpdateInterval, Converter={StaticResource updateIntervalToCheckedConverter}, ConverterParameter=0, Mode=TwoWay}"
Content="None" />
<RadioButton
x:Name="radioButtonTimerOne"
IsChecked="{Binding UpdateInterval, Converter={StaticResource updateIntervalToCheckedConverter}, ConverterParameter=1, Mode=TwoWay}"
Content="1" />
<RadioButton
x:Name="radioButtonTimerFive"
IsChecked="{Binding UpdateInterval, Converter={StaticResource updateIntervalToCheckedConverter}, ConverterParameter=5, Mode=TwoWay}"
Content="5" />
So now the "parameter" parameter on the "Convert" method will have the value "0", "1" or "5" depending on which RadioButton was checked. I think, though I'm not certain, that the parameter will be of type string, so you may have to take that into account when interrogating the value.
You could probably consider having a List<...> with different intervals. The list type should preferably be some custom type (e.g. UpdateInterval) or a KeyValuePair<K,V> to decouple what is shown to the user from what is an actual value.
Then you could have a ListBox bound to this list, and each ListBoxItem templated to show a RadioButton. Then, in the template, you bind radio button's IsChecked to ListBoxItem.IsSelected.
The final touch is just to bind your property to the ListBox's SelectedItem or SelectedValue.
This has been a very annoying problem for me.
The WPF RadioButton class has a bug that removes the binding for the IsChecked property when you assign multiple RadioButtons to the same GroupName. People have given many work arounds, but when I had to visit this again I came up with one that doesn't make me queasy.
So what you have to do is subclass the RadioButton class with this:
public class RadioButton: System.Windows.Controls.RadioButton
{
protected override void OnClick()
{
base.OnClick();
SetValue(CurrentValueProperty,CheckedValue);
}
public int CurrentValue
{
get { return (int)GetValue(CurrentValueProperty); }
set { SetValue(CurrentValueProperty, value); }
}
// Using a DependencyProperty as the backing store for CurrentValue. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CurrentValueProperty =
DependencyProperty.Register("CurrentValue", typeof(int), typeof(RadioButton), new FrameworkPropertyMetadata(0,FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, CurrentValue_Changed));
public static void CurrentValue_Changed(object sender, DependencyPropertyChangedEventArgs e)
{
((RadioButton)sender).IsChecked = ((RadioButton)sender).CurrentValue == ((RadioButton)sender).CheckedValue;
}
public int CheckedValue
{
get { return (int)GetValue(CheckedValueProperty); }
set { SetValue(CheckedValueProperty, value); }
}
// Using a DependencyProperty as the backing store for CheckedValue. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CheckedValueProperty =
DependencyProperty.Register("CheckedValue", typeof(int), typeof(RadioButton), new UIPropertyMetadata(0));
}
All this does is add two dependency properties so you can do an equality comparison.
So in XAML an example would be this:
<UserControl x:Class="MyClass"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:MVVMLibrary;assembly=MVVMLibrary"
Height="Auto" Width="Auto">
<c:RadioButton CurrentValue="{Binding MyValue}" CheckedValue="1" GroupName="SearchType" >Value 1</c:RadioButton>
<c:RadioButton Grid.Column="1" CurrentValue="{Binding MyValue}" CheckedValue="2" GroupName="SearchType" >Value 2</c:RadioButton>
</UserControl>
So If you notice all you do is
1) Bind to the CurrentValue property
2) Set the CheckedValue property to the value that would make the RadioButton checked
3) Set the RadioButtons to the same GroupName
If you notice i made CurrentValue and CheckedValue int type. The reason I did this is so that you could actually bind CurrentValue to an enumeration. I think this is awesome, but that's just my opinion which probably doesn't count for much. :)
Hope this helps somebody.
One possibility is to implement an IValueConverter and configure it passing the expected enumeration value for every RadioButton you need to bind, as I described here in my blog.