How to Bind ItemsSource of ComboBox in ControlTemplate? - c#

Situation
I have to change the content of the Flyout Item in GridView. So I am creating ControlTemplate in Page.Resources and setting it in ContentControl which is inside Flyout.
Problem
I have a ComboBox in ControlTemplate. Now I want to set the ItemsSource of ComboBox to List<string> (_easingType) which is declared in MainPage
Question
How to Bind/Set ItemsSource of ComboBox in ControlTemplate?
Code
I have removed the unnecessary parts of the code
XAML
<Page.Resources>
<ControlTemplate x:Key="BlurEditFlyout">
....
<ComboBox ItemsSource="{Bind it to the _esaingType}" />
....
<ControlTemplate x:Key="BlurEditFlyout">
</Page.Resources>
<GridView ItemsSource="{x:Bind _items}">
<GridView.ItemTemplate>
<DataTemplate x:DataType="local:MethodData">
<StackPanel>
....
<Button Visibility="{x:Bind EditButtonVisibility}">
<Button.Flyout>
<Flyout>
<Flyout.FlyoutPresenterStyle>
<Style TargetType="FlyoutPresenter">
<Setter Property="ScrollViewer.HorizontalScrollMode" Value="Disabled" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
</Style>
</Flyout.FlyoutPresenterStyle>
<ContentControl Template="{x:Bind FlyoutTemplate}"/>
</Flyout>
</Button.Flyout>
<SymbolIcon Symbol="Edit"/>
</Button>
....
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
Code Behind
public sealed partial class MainPage : Page
{
ObservableCollection<MethodData> _items = new ObservableCollection<MethodData>();
List<string> _easingType = new List<string>(Enum.GetNames(typeof(EasingType)).ToArray());
Dictionary<MethodName, ControlTemplate> _buttonFlyoutDictionary = new Dictionary<MethodName, ControlTemplate>();
public MainPage()
{
this.InitializeComponent();
LoadFlyoutResources();
_items.Add(GetMethodData(MethodName.Blur));
}
private void LoadFlyoutResources()
{
_buttonFlyoutDictionary.Add(MethodName.Blur, (ControlTemplate)Resources["BlurEditFlyout"]);
.....
}
private MethodData GetMethodData(MethodName methodName)
{
_buttonFlyoutDictionary.TryGetValue(methodName, out ControlTemplate flyoutTemplate);
return new MethodData(methodName, flyoutTemplate);
}
}
public class MethodData
{
public string Name { get; set; }
public ControlTemplate FlyoutTemplate { get; set; }
public Visibility EditButtonVisibility { get; set; }
public MethodData(MethodName name, ControlTemplate flyoutTemplate)
{
Name = name.ToString();
FlyoutTemplate = flyoutTemplate;
EditButtonVisibility = (name == MethodName.Then) ? Visibility.Collapsed : Visibility.Visible;
}
}
public enum MethodName
{
Blur,
....
}
Full Code
AnimationSetSamplePage.zip

Your DataContext in the Flyout control is actually each item in "_items". You'll want to create a DataContext proxy to get to your Page's DataContext. You can follow either of these two links to create the proxy.
https://weblogs.asp.net/dwahlin/creating-a-silverlight-datacontext-proxy-to-simplify-data-binding-in-nested-controls
http://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/
The gist of it is you'll want to create a proxy that you can reference as a static resource. Following the first link, you'll do something like this:
public class DataContextProxy : FrameworkElement
{
public DataContextProxy()
{
this.Loaded += new RoutedEventHandler(DataContextProxy_Loaded);
}
void DataContextProxy_Loaded(object sender, RoutedEventArgs e)
{
Binding binding = new Binding();
if (!String.IsNullOrEmpty(BindingPropertyName))
{
binding.Path = new PropertyPath(BindingPropertyName);
}
binding.Source = this.DataContext;
binding.Mode = BindingMode;
this.SetBinding(DataContextProxy.DataSourceProperty, binding);
}
public Object DataSource
{
get { return (Object)GetValue(DataSourceProperty); }
set { SetValue(DataSourceProperty, value); }
}
public static readonly DependencyProperty DataSourceProperty =
DependencyProperty.Register("DataSource", typeof(Object), typeof(DataContextProxy), null);
public string BindingPropertyName { get; set; }
public BindingMode BindingMode { get; set; }
}
You should use public access modifier for _easingType
public List<string> _easingType = new List<string>(Enum.GetNames(typeof(EasingType)).ToArray());
In MainPage.xaml
<Page.Resources>
<local:DataContextProxy x:Key="DataContextProxy" />
<ControlTemplate x:Key="BlurEditFlyout">
....
<ComboBox ItemsSource="{Binding Source={StaticResource DataContextProxy}, Path=DataSource._easingType}" />
....
<ControlTemplate x:Key="BlurEditFlyout">
</Page.Resources>
...

How to Bind/Set ItemsSource of ComboBox in ControlTemplate?
I'm not sure if you have deep reasons for asking this question, but directly to reply this question, we could just set the string list _esaingType as the value of DataContext property and binding it. For example:
XAML
<Page.Resources>
<ControlTemplate TargetType="FlyoutPresenter" x:Key="BlurEditFlyout" >
...
<ComboBox ItemsSource="{Binding}" />
...
</ControlTemplate>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Button>
<Button.Flyout>
<Flyout>
<Flyout.FlyoutPresenterStyle>
<Style TargetType="FlyoutPresenter">
<Setter Property="ScrollViewer.HorizontalScrollMode" Value="Disabled" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
<Setter Property="Template" Value="{StaticResource BlurEditFlyout}">
</Setter>
</Style>
</Flyout.FlyoutPresenterStyle>
<!--<ContentControl Template="{StaticResource BlurEditFlyout}"/>-->
</Flyout>
</Button.Flyout>
<SymbolIcon Symbol="Edit"/>
</Button>
</Grid>
Code behind
List<string> _easingType = new List<string>();
public MainPage()
{
this.InitializeComponent();
_easingType.Add("test2");
_easingType.Add("test1");
this.DataContext = _easingType;
}
Any concerns on this way or any issues when using this on your side please kindly tell me I will follow up in time. More details please reference Data binding in depth.

Related

WPF list does not refresh

I'm trying to create a new page in a WPF application. It is an "old" project, discovering the project and the language (I know C/C++, not C# nor XAML). In that page, I have to put a list of "rapport". But I can't refresh that list with new items, nor refresh the items.
I can't put that list in XAML, I have to use a C# variable. I try a lot of things, like List, observable list, refresh, binding, trigger event from expander, so a lot of code may be useless / unreachable.
And for a precision, piramidHandler.GetListParamReport(); has to be in the piramid class.
Thank's a lot for your help, pardon my English, still not my native language, but I try to make my best.
Rapports.xaml :
<Expander Header="{x:Static resx:StringResources.Lib_TabRapports}" VerticalAlignment="Top" Grid.Row="2" IsExpanded="False" IsEnabled="True" Expanded="ExpanderRapport">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!--First row for controls-->
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="650" />
<ColumnDefinition Width="650" />
</Grid.ColumnDefinitions>
</Grid>
<DataGrid ItemsSource="{Binding ListRapports}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserResizeColumns="False" Name="RapportGrid"
CanUserReorderColumns="False" Style="{StaticResource AzureDataGrid}" Grid.Row="1" FrozenColumnCount="2"
ScrollViewer.CanContentScroll="True" ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.HorizontalScrollBarVisibility="Auto">
<DataGrid.Resources>
<Style x:Key="AlignBottomColumnHeader" BasedOn="{StaticResource AzureDataGridColumnHeader}" TargetType="DataGridColumnHeader">
<Setter Property="VerticalContentAlignment" Value="Bottom" />
</Style>
<Style x:Key="RotatedColumnHeader" BasedOn="{StaticResource AzureDataGridColumnHeader}" TargetType="DataGridColumnHeader">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
<Setter Property="Margin" Value="-4,0,0,0" />
<Setter Property="BorderBrush" Value="White" />
<Setter Property="LayoutTransform">
<Setter.Value>
<RotateTransform Angle="-90" />
</Setter.Value>
</Setter>
</Style>
</DataGrid.Resources>
RapportViewModel.cs :
public sealed partial class Piramid
{
internal ObservableCollection<ViewModels.Rapport> listRapports;
public string GetRapportsList()
{
return piramidHandler.GetListParamReport();
}
public ObservableCollection<ViewModels.Rapport> ReloadRapportsLists()
{
var uniqueListRapport = new HashSet<ViewModels.Rapport>();
string gabaritsXML = GetRapportsList();
// [...] Fill uniqueListRapport
return new ObservableCollection<ViewModels.Rapport>(uniqueListRapport.ToList());
}
}
public class TabRapport : ViewModelBase
{
#region Properties
public TabRapport()
{
}
public ObservableCollection<ViewModels.Rapport> ListRapports
{
get
{
ObservableCollection<Rapport> test;
test = Piramid.Instance.ReloadRapportsLists();
if (test.Count == 0)
{
ViewModels.Rapport current = new ViewModels.Rapport
{
IdRapport = 52,
NameRapport = "This is a try"
};
test.Add(current);
ViewModels.Rapport current2 = new ViewModels.Rapport
{
IdRapport = 54,
NameRapport = "Second try"
};
test.Add(current2);
}
return test;
}
}
#endregion Properties
#region commands
// Useless in the context
#endregion commands
}
public class Rapport : ViewModelBase
{
public Rapport()
{
idRapport = -1;
}
public Rapport(Rapport e)
{
idRapport = e.IdRapport;
nameRapport = e.NameRapport;
}
private int idRapport;
private string nameRapport;
public int IdRapport
{
get => idRapport;
set => idRapport = value;
}
public string NameRapport
{
get => nameRapport;
set => nameRapport = value;
}
}
Rapports.xaml.cs :
public partial class Rapports : UserControl, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
OnTargetUpdated();
}
private void ExpanderRapport(object sender, RoutedEventArgs args)
{
OnTargetUpdated();
}
public Rapports()
{
InitializeComponent();
Thread.CurrentThread.CurrentCulture = App.AppCultureInfo;
Thread.CurrentThread.CurrentUICulture = App.AppCultureInfo;
}
public void OnTargetUpdated()
{
RapportsRoot.Reload();
RapportGrid.Items.Refresh();
}
public void OnTargetUpdated(object sender, System.EventArgs e)
{
RapportsRoot.Reload();
RapportGrid.Items.Refresh();
}
}
EDIT :
DataContext : DataContext="{Binding Source={StaticResource Locator}, Path=OngletRapport}">
Reference to :
public TabRapport OngletRapport
{
get
{
return ServiceLocator.Current.GetInstance<TabRapport>();
}
}
EDIT 2 : Added code in the RapportViewModel.cs. My current try just show "This is a try" and "second try" as a list, not able to change it after setting data in listRapport
Okay, I finally find the answer.
I need to use ObservableObject.RaisePropertyChanged("ListRapports"); at the end of all background traitement, forcing the listRapports to refresh all data and items number.
Thank's a lot for all your help :)

How to apply a style to the first WPF ContentPresenter found under a gridview but not any deeper

I would like to be able to style the ContentPresenter used for rendering the cells of a GridView. However if I set a style targeting ContentPresenter generally then it will target ContentPresenter instances within ContentPresenters which I do not want to do. I only want to style the first level of content presenters found.
Is this possible? Something like this
<Style Target="GridView">
<Style.Resource>
<Style Target="ContentPresenter" Depth=1>
<Setter Property="Margin" Value="1"/>
</Style>
</Style.Resources>
</Style>
where Depth=1 is an invented property.
You could possibly do this with a DataTemplateSelector - by setting a style for a ContentPresenter and ensuring it used a ContentTemplateSelector.
My example is simplified and doesn't use a GridView - but the concept is the same.
If you had the following DataTemplateSelector:
public class DepthTemplateSelector : DataTemplateSelector
{
public DataTemplate InDepthTemplate { get; set; }
public Type Type { get; set; }
public int Depth { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var next = container;
int itemsControlCount = 0;
while (VisualTreeHelper.GetParent(next) != null)
{
var current = VisualTreeHelper.GetParent(next);
if (current.GetType() == this.Type)
{
itemsControlCount++;
}
next = current;
}
if (itemsControlCount <= this.Depth)
{
return this.InDepthTemplate;
}
return base.SelectTemplate(item, container);
}
}
Then wire this up in XAML with whatever template you wanted to use for content presenters with less than a certain depth:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:w="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<w:DepthTemplateSelector x:Key="DepthTemplateSelector" Depth="2" Type="{x:Type ContentPresenter}">
<w:DepthTemplateSelector.InDepthTemplate>
<DataTemplate DataType="{x:Type w:Model}">
<StackPanel>
<TextBlock Text="{Binding Description}" Foreground="Red" />
<ItemsControl ItemsSource="{Binding Models}" Margin="20,0,0,0" />
</StackPanel>
</DataTemplate>
</w:DepthTemplateSelector.InDepthTemplate>
</w:DepthTemplateSelector>
<Style TargetType="{x:Type ContentPresenter}">
<Setter Property="ContentTemplateSelector" Value="{StaticResource DepthTemplateSelector}" />
</Style>
<DataTemplate DataType="{x:Type w:Model}">
<StackPanel>
<TextBlock Text="{Binding Description}" />
<ItemsControl ItemsSource="{Binding Models}" Margin="20,0,0,0" />
</StackPanel>
</DataTemplate>
</Window.Resources>
<Window.DataContext>
<w:ViewModel />
</Window.DataContext>
<ListView ItemsSource="{Binding Models}" />
</Window>
So the XAML creates and configures the DataTemplateSelector but also ensures all ContentPresenters use it by setting a default ContentPresenter style.
This will then give you the following effect (with Depth set to 2):
This is based on the following view model, which uses a recursive structure to illustrate the point:
public class ViewModel
{
public ViewModel()
{
this.Models = new List<Model>
{
new Model
{
Description = "ModelA",
Models = new List<Model>
{
new Model { Description = "ModelA1" },
new Model { Description = "ModelA2" }
}
},
new Model
{
Description = "ModelB",
Models = new List<Model>
{
new Model { Description = "ModelB1" },
new Model
{
Description = "ModelB2",
Models = new List<Model>
{
new Model { Description = "ModelB2i" },
new Model { Description = "ModelB2ii" }
}
}
}
}
};
}
public List<Model> Models { get; set; }
}
public class Model
{
public string Description { get; set; }
public List<Model> Models { get; set; }
}

Execute method when tab is selected

I have the following classes / XAML that define my tabs (using SimpleMVVM in case that matters):
Tabs Interface
public interface ITabViewModel
{
String Header { get; set; }
Visibility Visibility { get; set; }
void TabSelected();
}
Tabs VM
public class TabsViewModel : ViewModelBase<TabsViewModel>
{
#region Properties
public ObservableCollection<ITabViewModel> Tabs { get; set; }
public object SelectedTabViewModel
{
get
{
if (this._SelectedTabViewModel == null)
{
_SelectedTabViewModel = Tabs[0];
}
return _SelectedTabViewModel;
}
set
{
if (this._SelectedTabViewModel != value)
{
this._SelectedTabViewModel = value;
NotifyPropertyChanged(m => m.SelectedTabViewModel);
}
}
}
private object _SelectedTabViewModel;
#endregion Properties
#region Constructors
// Default ctor
public TabsViewModel()
{
Tabs = new ObservableCollection<ITabViewModel>();
Tabs.Add((App.Current.Resources["Locator"] as ViewModelLocator).PropertiesViewModel);
Tabs.Add((App.Current.Resources["Locator"] as ViewModelLocator).SystemSetupViewModel);
}
}
Tabs UserControl
<UserControl x:Class="AutomatedSQLMigration.Views.TabsUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:v="clr-namespace:AutomatedSQLMigration.Views"
xmlns:vm="clr-namespace:AutomatedSQLMigration.ViewModels"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
DataContext="{Binding TabsViewModel, Source={StaticResource Locator}}">
<TabControl ItemsSource="{Binding Tabs}"
SelectedItem="{Binding SelectedTabViewModel}">
<TabControl.Resources>
<DataTemplate DataType="{x:Type vm:PropertiesViewModel}">
<v:PropertiesUserControl />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:SystemSetupViewModel}">
<v:SystemSetupUserControl />
</DataTemplate>
</TabControl.Resources>
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding Header}" />
<Setter Property="Width" Value="120" />
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
</UserControl>
Properties VM
...
public void TabSelected()
{
Log.Write(LogLevel.Debug, "Selected tab 'Rules'");
}
...
I would like to wire this up such that when the tab is selected, the TabSelected() method is fired for the selected tab. Can someone provide an example of how to do this?
I found another post that mentions this method:
TabItem item = new TabItem();
MyCustomControl mcc = new MyCustomControl();
item.Content = mcc;
Selector.AddSelectedHandler(item, (s,e) =>
{
selectedControl = mcc;
});
but am not sure how I would implement this? Would I apply this to the TabControl VM or each individual user control VM?
How about adding the line in the selected tab setter:
this._SelectedTabViewModel.TabSelected();

defining bindings for elements in a collection in xaml wont work

i have a simple Control with a collection of elements. I want to add elements in xaml and bind to the element.
However when i bind to Bar.Value in xaml it never works. Minimal example:
[ContentProperty("Bars")]
public class FooControl : Control
{
private ObservableCollection<IBar> _bars = new ObservableCollection<IBar>();
public ObservableCollection<IBar> Bars { get { return _bars; } }
}
public interface IBar
{
string Value { get; }
}
public class Bar : DependencyObject, IBar
{
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(string), typeof(Bar), new PropertyMetadata("<not set>"));
public string Value
{
get { return (string)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
}
<Window x:Class="WpfTestApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:this="clr-namespace:WpfTestApplication"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="MainWindow" Height="200" Width="1000">
<Window.Resources>
<Style TargetType="this:FooControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="this:FooControl">
<ItemsControl ItemsSource="{Binding Bars, RelativeSource={RelativeSource TemplatedParent}}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Value}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Window.DataContext>
<sys:String>from DataContext</sys:String>
</Window.DataContext>
<Grid>
<this:FooControl>
<this:Bar Value="directly set"/>
<this:Bar Value="{Binding Source=from_binding_source}"/>
<this:Bar Value="{Binding}"/>
<this:Bar Value="{Binding Text, ElementName=SomeTextBlock}"/>
</this:FooControl>
<TextBlock Text="from TextBox" Name="SomeTextBlock" Visibility="Collapsed"/>
</Grid>
</Window>
output
directly set
from_binding_source
"<not set>"
"<not set>"
debug output
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=Text; DataItem=null; target element is 'Bar' (HashCode=26568931); target property is 'Value' (type 'String')
Any suggestion how to get it to work?
My current workaround is to define the bindings in code but this is a lot more code and looking at the xaml its not obvious which bindings do exists. (see my answer for workaround code)
dont know if this helps but
[ContentProperty("Bars")]
public class FooControl : Control
{
private ObservableCollection<object> _bars = new ObservableCollection<object>();
public ObservableCollection<object> Bars { get { return _bars; } }
}
xaml
<this:FooControl>
<this:Bar Value="directly set"/>
<this:Bar Value="{Binding Source=from_binding_source}"/>
<TextBlock Text="{Binding}"/>
<TextBlock Text="{Binding Text, ElementName=SomeTextBlock}"/>
</this:FooControl>
you get your desired result
my workaround so far
<this:Bar x:Name="bar3" />
<this:Bar x:Name="bar4" />
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
var bar3 = (DependencyObject)FindName("bar3");
BindingOperations.SetBinding(bar3, Bar.ValueProperty, new Binding("DataContext") { Source = this });
var bar4 = (DependencyObject)FindName("bar4");
BindingOperations.SetBinding(bar4, Bar.ValueProperty, new Binding("Text") { Source = FindName("SomeTextBlock") });
}

Chaining (Dependency) Properties to nested control

I have a ListBox with a GroupStyle that contains another ListBox.
Now I want to filter the Items of the nested ListBox depending on the group name of the parent ListBox.
In the code below I tried to chain the GroupItem.Name.Name property to the GroupName property of the ViewModel of the nested ListBox, but this didn't work out so well.
Essentially the GroupNameIn Property is filled by the GroupItems' name(the TextBlock Text) and then sets the GroupNameOut Property to the same value in the PropertyChangedCallback. But the problem is that the GroupName Property of the NestedItemsViewModel to which GroupNameOut is bound to doesn't update.
Are there some mistakes in my approach or is there even a simpler/better way to achieve this behavior?
I would be very grateful if someone could point me in the right direction.
GroupStyle of the parent ListBox:
<Style x:Key="MyListBoxGroupStyle" TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<StackPanel Name="container" Width="Auto" Orientation="Vertical">
<TextBlock Name="groupNameTextBlock" Text="{Binding Path=Name.Name}"/>
<ItemsPresenter/>
<MyNestedListBox
DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBox}}, Path=NestedItemsDataContext}"
ItemsSource="{Binding NestedItems}"
GroupNameIn="{Binding ElementName=groupNameTextBlock, Path=Text}"
GroupNameOut="{Binding Path=GroupName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The nested ListBox:
public class MyNestedListBox : ListBox
{
static MyNestedListBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyNestedListBox), new FrameworkPropertyMetadata(typeof(MyNestedListBox)));
}
public string GroupNameIn
{
get { return (string)GetValue(GroupNameInProperty); }
set { SetValue(GroupNameInProperty, value); }
}
public string GroupNameOut
{
get { return (string)GetValue(GroupNameOutProperty); }
set { SetValue(GroupNameOutProperty, value); }
}
// DepenencyProperties
public static readonly DependencyProperty GroupNameInProperty =
DependencyProperty.Register("GroupNameIn", typeof(string), typeof(MyNestedListBox), new UIPropertyMetadata(null) { PropertyChangedCallback = (obj, target) =>
{
obj.SetValue(GroupNameOutProperty, target.NewValue);
}
});
public static readonly DependencyProperty GroupNameOutProperty =
DependencyProperty.Register("GroupNameOut", typeof(string), typeof(MyNestedListBox), new UIPropertyMetadata(null));
}
ViewModel bound to the nested ListBox:
public class NestedItemsViewModel : ViewModelBase
{
private string _groupName;
public ObservableCollection<NestedItem> NestedItems { get; set; }
public string GroupName
{
get
{
return _groupName;
}
set
{
_groupName = value;
OnPropertyChanged(() => GroupName);
}
}
public NestedItemsViewModel()
{
NestedItems = new ObservableCollection<NestedItem>();
}
}

Categories

Resources