I have an ObservableCollection of ViewModels in my main ViewModel. The binding seems to work fine since I can switch views. However, raising the ViewModelBase OnPropertyChanged method (which work for other stuff) in an element of the ObservableCollection result in a null PropertyChanged value in ViewModelBase.
Here's my main code snippets:
In my main ViewModel Constructor:
public EditorViewModel()
{
base.DisplayName = Strings.EditorName;
_availableEditors = new ObservableCollection<ViewModelBase>();
AvailableEditors.Add(new GBARomViewModel(646, 384));
AvailableEditors.Add(new MonsterViewModel(800, 500));
CurrentEditor = _availableEditors[0];
}
At GBA ROM loading, ViewModel and Model properties are updated:
void RequestOpenRom()
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.DefaultExt = ".gba";
dlg.Filter = "GBA ROM (.gba)|*.gba|All files (*.*)|*.*";
dlg.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
Nullable<bool> result = dlg.ShowDialog();
if (result == true)
{
if(CurrentEditor is GBARomViewModel)
{
(CurrentEditor as GBARomViewModel).ReadRom(dlg.FileName);
}
}
}
In my main View: Variation of TabControl (to have view switching and view states preservation).
<controls:TabControlEx ItemsSource="{Binding AvailableEditors}"
SelectedItem="{Binding CurrentEditor}"
Style="{StaticResource BlankTabControlTemplate}"
MinWidth="{Binding CurrentEditorWidth}"
MinHeight="{Binding CurrentEditorHeight}"
MaxWidth="{Binding CurrentEditorWidth}"
MaxHeight="{Binding CurrentEditorHeight}"
Width="{Binding CurrentEditorWidth}"
Height="{Binding CurrentEditorHeight}"
HorizontalAlignment="Left"
VerticalAlignment="Top">
<controls:TabControlEx.Resources>
<DataTemplate DataType="{x:Type vm:GBARomViewModel}">
<vw:GBARomView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:MonsterViewModel}">
<vw:MonsterView />
</DataTemplate>
</controls:TabControlEx.Resources>
</controls:TabControlEx>
In GBARomViewModel (child ViewModel, element of AvailableEditors)
public String CRC32
{
get
{
return _rom.CRC32;
}
set
{
if (value.Equals(_rom.CRC32))
{
return;
}
_rom.CRC32 = value;
OnPropertyChanged("CRC32");
}
}
Property binding in child View
Now this is a UserControl so I'll put its code as well after. Other properties at startup work such as LabelWidth and the LabelValue. Giving a default value to TextBoxValue in XAML also work.
<StackPanel VerticalAlignment="Bottom" HorizontalAlignment="Left" Margin="10, 0, 0, 10" Width="300">
<dlb:DefaultLabelBox LabelWidth="82" TextBoxWidth="100" HorizontalAlignment="Left" LabelValue="{x:Static p:Strings.RomTitle}" TextBoxValue="{Binding Title}" />
<dlb:DefaultLabelBox LabelWidth="82" TextBoxWidth="100" HorizontalAlignment="Left" LabelValue="{x:Static p:Strings.RomGameCode}" TextBoxValue="{Binding GameCode}" />
<dlb:DefaultLabelBox LabelWidth="82" TextBoxWidth="100" HorizontalAlignment="Left" LabelValue="{x:Static p:Strings.RomRomSize}" TextBoxValue="{Binding RomSize}" />
<dlb:DefaultLabelBox LabelWidth="82" TextBoxWidth="100" HorizontalAlignment="Left" LabelValue="{x:Static p:Strings.RomCRC32}" TextBoxValue="{Binding CRC32}" />
<dlb:DefaultLabelBox LabelWidth="82" TextBoxWidth="200" HorizontalAlignment="Left" LabelValue="{x:Static p:Strings.RomMD5Checksum}" TextBoxValue="{Binding MD5Checksum}"/>
</StackPanel>
DefaultLabelBox.cs
<UserControl x:Name="uc">
<StackPanel>
<TextBlock Text="{Binding Path=LabelValue, ElementName=uc}"
Width="{Binding Path=LabelWidth, ElementName=uc}"/>
<Label Content="{Binding Path=TextBoxValue, Mode=OneWay, ElementName=uc}"
Width="{Binding Path=TextBoxWidth, ElementName=uc}"/>
</StackPanel>
</UserControl>
DefaultLabelBox.xaml.cs
public string TextBoxValue
{
get {
return (string)GetValue(TextBoxValueProperty);
}
set {
SetValue(TextBoxValueProperty, value);
}
}
public static readonly DependencyProperty TextBoxValueProperty =
DependencyProperty.Register("TextBoxValue", typeof(string), typeof(DefaultLabelBox), new PropertyMetadata(default(string)));
Control Template
<Style TargetType="dlb:DefaultLabelBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="dlb:DefaultLabelBox">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding LabelValue, RelativeSource={RelativeSource TemplatedParent}}"
MinWidth="20"
Width="{Binding LabelWidth, RelativeSource={RelativeSource TemplatedParent}}"
VerticalAlignment="Center"
FontFamily="Mangal"
Height="20"
FontSize="13"/>
<Label Content="{Binding TextBoxValue, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"
BorderBrush="{StaticResource DefaultLabelBoxBorderBrush}"
BorderThickness="1"
Padding="1,1,1,1"
Background="{StaticResource DefaultLabelBoxBackgroundBrush}"
Foreground="{StaticResource DefaultLabelBoxForeground}"
MinWidth="60"
Height="20"
VerticalAlignment="Center"
FontFamily="Mangal"
Width="{Binding TextBoxWidth, RelativeSource={RelativeSource TemplatedParent}}"
FontSize="13"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I tried a few things but being new to MVVM I don't know if I have a DataContext issue of a binding one. Any help would be appreciated.
Edit: I made changes to some code to illustrate the working solution for me as well as adding the ControlTemplate I had forgot. I'm not sure if Mode=OneWay is mandatory in UserControl and ControlTemplate but it's working now so I'm leaving it as it is.
In order to make a binding like
<dlb:DefaultLabelBox ... TextBoxValue="{Binding CRC32, Mode=TwoWay}" />
work, the DefaultLabelBox needs to inherit its DataContext from its parent control (this is btw. the reason why a UserControl should never explicitly set its DataContext).
However, the "internal" bindings in the UserControl's XAML then need an explicitly specified Source or RelativeSource or ElementName.
So they should (for example) look like this:
<UserControl ... x:Name="uc">
<StackPanel>
<TextBlock
Text="{Binding Path=LabelValue, ElementName=uc}"
Width="{Binding Path=LabelWidth, ElementName=uc}"/>
<TextBox
Text="{Binding Path=TextBoxValue, Mode=TwoWay, ElementName=uc}"
Width="{Binding Path=TextBoxWidth, ElementName=uc}"/>
</StackPanel>
</UserControl>
Related
I am using ItemsControl under DataTemplate. I want to sort ItemsControl ic using id column.
<DataTemplate x:Key="With">
<DockPanel>
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<TextBlock Text="{Binding Path=fil}" Style="{StaticResource Fixed}" Margin="0,0,6,8" />
<mui:ModernButton IconData="{StaticResource PlayIconData}" Click="FullPlayback" Margin="0,0,6,8" ></mui:ModernButton>
</StackPanel>
<StackPanel DockPanel.Dock="Left" Orientation="Horizontal">
<TextBlock Text="{Binding Path=e1}" Foreground="Red" Style="{StaticResource Fixed}" Margin="0,0,6,8" />
<TextBlock Text="{Binding Path=m1}" Foreground="LightSalmon" Style="{StaticResource Fixed}" Margin="0,0,6,8" />
<TextBlock Text="{Binding Path=n1}" Foreground="Orange" Style="{StaticResource Fixed}" Margin="0,0,6,8" />
<TextBlock Text="{Binding Path=m2}" Foreground="LightGreen" Style="{StaticResource Fixed}" Margin="0,0,6,8" />
<TextBlock Text="{Binding Path=m3}" Foreground="Green" Style="{StaticResource Fixed}" Margin="0,0,6,8" />
<TextBlock Text="{Binding ElementName=H1, Path=Items.Count,Mode=OneWay}" Style="{StaticResource Fixed}" Margin="0,0,6,8" />
</StackPanel>
<ItemsControl Name="ic" DockPanel.Dock="Bottom" ItemsSource="{Binding Path=seg}" ItemsPanel="{StaticResource HSPanel}">
<ControlTemplate TargetType="ItemsControl">
<Border>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsPresenter />
</ScrollViewer>
</Border>
</ControlTemplate>
</ItemsControl.Template>
</ItemsControl>
</DockPanel>
</DataTemplate>
i tried below options but sorting is not working.
1.Tried sorting in constructor of the user control like following (code behind)
ic.Items.SortDescriptions.Clear();
ic.Items.SortDescriptions.Add(new SortDescription("id", ListSortDirection.Ascending));
ic.Items.Refresh();
But i am unable to access ic in code behind. Errors says "ic does not exists in current context"
2.Tried CollectionViewSource under ItemsControl in xaml which is also not working.
<ItemsControl x:Name="ic" DockPanel.Dock="Bottom" ItemsSource="{Binding Path=segments}" ItemsPanel="{StaticResource HSPanel}">
<ItemsControl.Resources>
<CollectionViewSource x:Key="segments" Source="{Binding seg}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="id" Direction="Ascending"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</ItemsControl.Resources>
<ItemsControl.Template>
3.Tried CollectionViewSource under ControlTemplate in xaml which is also not working.
<ControlTemplate TargetType="ItemsControl">
<ControlTemplate.Resources>
<CollectionViewSource x:Key="segments" Source="{Binding seg}" >
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="sortId" Direction="Ascending"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</ControlTemplate.Resources>
But i initialised Loaded event of ic and tried to do sorting from there.In this case initially when the page loads, the items are not sorted. But when i move to another user control and come back to this current user control, the items looks sorted out perfectly.
private void ic_Loaded(object sender, RoutedEventArgs e)
{
ItemsControl ic = (ItemsControl)sender;
ic.Items.SortDescriptions.Clear();
ic.Items.SortDescriptions.Add(new SortDescription("id", ListSortDirection.Ascending));
ic.Items.Refresh();
}
You have two options :
1 - Sort your source collection (seg) in View Model.
2 - Use CollectionViewSource (http://msdn.microsoft.com/fr-fr/library/system.windows.data.collectionviewsource.aspx).
Here is a full working exemple:
I have added this code in to an empty WPF window:
public class SomeVM
{
public ObservableCollection<SomeItemVM> Items { get; set; }
public SomeVM()
{
Items = new ObservableCollection<SomeItemVM>();
}
}
public class SomeItemVM
{
public string id { get; set; }
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
//Create some VM
SomeVM data = new SomeVM();
data.Items.Add(new SomeItemVM() { id = "3" });
data.Items.Add(new SomeItemVM() { id = "4" });
data.Items.Add(new SomeItemVM() { id = "1" });
data.Items.Add(new SomeItemVM() { id = "2" });
this.DataContext = data;
}
}
Then in XAML I add a content control that will hold the VM and a DataTemplate that will describe the way the VM will be displayed:
<Window.Resources>
<DataTemplate x:Key="With">
<DockPanel>
<DockPanel.Resources>
<!-- CollectionViewSource should be declared as a resource of parent container of the ItemsControl.
Otherwise there will be an exception of StaticResourceHolder -->
<CollectionViewSource x:Key="segments" Source="{Binding Items}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="id" Direction="Ascending"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</DockPanel.Resources>
<ItemsControl Name="ic" DockPanel.Dock="Bottom" ItemsSource="{Binding Source={StaticResource segments}}">
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<Border>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsPresenter />
</ScrollViewer>
</Border>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding id}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DockPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<ContentControl Content="{Binding}" ContentTemplate="{StaticResource With}"/>
</Grid>
The resulting ItemsControl will display sorted items.
Finally i solved the sorting problem.
I am binding segments(observablecollection< seg>) to the itemscontrol. Previously In code behind i was generating segments directly like below
segments[0].name="GHI";
segments[0].age=40;
segments[1].name="ABC";
segments[1].age=20;
segments[2].name="DEF";
segments[2].age=30;
Instead of generating segments directly, i created another variable objSegments and generated the values like below.
objSegments[0].name="GHI";
objSegments[0].age=40;
objSegments[1].name="ABC";
objSegments[1].age=20;
objSegments[2].name="DEF";
objSegments[2].age=30;
After generating all the values, sorting is done and assigned to segments using the code below.
ObservableCollection<seg> sortedSegments = new ObservableCollection<seg>(objSegments.OrderBy(c => c.id));
foreach (var objSeg in sortedSegments)
{
segments.Add(objSeg);
}
It worked fine for me.
I have a Data template
<DataTemplate x:Key="ConnectorItemFactory">
<Button Style="{StaticResource TextOnlyActionTileButtonStyle}" Margin="0,0,5,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
Content="{Binding}"
ContentTemplate="{StaticResource TileTemplate}"
Command="{StaticResource NavigationCommand}"
CommandParameter="{Binding}"
Height="156"
Width="156"
>
<i:Interaction.Behaviors>
<UICommon:XboxBehavior VuiBinding="{Binding VuiTitle}"/>
</i:Interaction.Behaviors>
</Button>
</DataTemplate>
as a ContentTemplate it is used another data template
<DataTemplate x:Key="TileTemplate">
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Background="{StaticResource ActionButtonBackgroundBrush}">
<StackPanel Orientation="Vertical" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="7,7,7,4">
<Controls:TrimmedTextBlock Text="{Binding Title}" Style="{StaticResource TextOnlyTileTitleStyle}" TextWrapping="Wrap" />
<Controls:TrimmedTextBlock Text="{Binding Converter={StaticResource SubtitleTextFormatter}}" Style="{StaticResource TextOnlyTileSubtitleStyle}"/>
</StackPanel>
</Grid>
</DataTemplate>
I'm using a TemplateFactory to load the content template
public class GridTemplateFactory : ModelViewTemplateFactory
{
protected override void OnContentChanged(object oldContent, object newContent)
{
base.OnContentChanged(oldContent, newContent);
var dataTemplate = Application.Current.Resources["ConnectorItemFactory"] as DataTemplate;
// var grid = ((Button)dataTemplate.LoadContent()).ContentTemplate.LoadContent();
// ((Grid)grid).Background = new SolidColorBrush(Colors.Orange);
// ((Button)dataTemplate.LoadContent()).ContentTemplate.LoadContent().SetValue(Grid.BackgroundProperty, new SolidColorBrush(Colors.Orange));
this.ContentTemplate = dataTemplate;
}
}
In the OnContentChanged method I want to change the Grid background color from the TileTemplate data template.
I tried to do it like in commented code above, but it doesn't work. How can I change the color here?
I'm trying to make my popup widget to be on top in a map but setting Canvas.ZOrder doesn't help.
Here is XAML:
<m:Map x:Name="MainMap"
Margin="0,6,3,3"
ZoomLevel="{Binding MapZoomLevel, Mode=TwoWay}"
Center="{Binding MapCenter, Mode=TwoWay}"
CopyrightVisibility="Collapsed"
CredentialsProvider="{Binding BingCredentialsProvider}"
UseInertia="True"
Mode="Road" Grid.Column="2" Grid.Row="1">
<m:MapItemsControl ItemsSource="{Binding Source={StaticResource WorkLayerData}}">
<m:MapItemsControl.ItemTemplate>
<DataTemplate>
<Canvas
m:MapLayer.Position="{Binding Location}">
<Button
Width="{Binding PushpinWidth}" Height="{Binding PushpinWidth}"
Margin="{Binding PushpinMargin}"
Style="{StaticResource LooklessButtonStyle}"
Command="{Binding DataContext.SelectedPushpinChangedCommand, ElementName=LayoutRoot}"
CommandParameter="{Binding}"
Cursor="Hand">
<Ellipse
Width="{Binding PushpinWidth}" Height="{Binding PushpinWidth}" Stroke="Black" Fill="{Binding IsGPSDataRecent, Converter={StaticResource BoolToGreenRedBrushConverter}}" StrokeThickness="1">
<ToolTipService.ToolTip>
<TextBlock Text="{Binding DeviceId}" />
</ToolTipService.ToolTip>
</Ellipse>
</Button>
<!-- Show black dot over actual GPS point -->
<Ellipse
Width="10" Height="10" Stroke="Black" Fill="Black" StrokeThickness="1"
Margin="-5,-5,0,0"
Visibility="{Binding IsSelected, Converter={StaticResource BoolToVisibilityConverter}}" />
<Border
Width="200"
BorderThickness="1" BorderBrush="DarkGray"
Visibility="{Binding IsSelected, Converter={StaticResource BoolToVisibilityConverter}}">
<Border.Effect>
<DropShadowEffect BlurRadius="5" Color="#FF000000" Opacity="0.5" ShadowDepth="2" />
</Border.Effect>
<ContentControl Template="{StaticResource TrackedAssetControlTemplate}" />
</Border>
</Canvas>
</DataTemplate>
</m:MapItemsControl.ItemTemplate>
</m:MapItemsControl>
</m:Map>
I tried to set ZIndex on a border but no luck.
Here is how it looks when IsSelected = true (see other dots with ZIndex higher on top)
In order to bring an item in a MapItemsControl to front it is necessary to set the ZIndex of the item container. You can do that in code behind by retrieving the item container from the MapItemsControl's ItemContainerGenerator.
In case you don't want that, you could apply an attached helper property to the top-level container (the Canvas) in the DataTemplate for your map items. As this Canvas is the direct child of the item container, the helper property would have to set the ZIndex of the visual parent of the Canvas. If that sounds weird, here is the code for the attached property, in a helper class called MapItem:
public class MapItem
{
public static readonly DependencyProperty ZIndexProperty =
DependencyProperty.RegisterAttached("ZIndex", typeof(int),
typeof(MapItem), new PropertyMetadata(ZIndexChanged));
public static int GetZIndex(DependencyObject obj)
{
return (int)obj.GetValue(ZIndexProperty);
}
public static void SetZIndex(DependencyObject obj, int value)
{
obj.SetValue(ZIndexProperty, value);
}
private static void ZIndexChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
// set ZIndex on parent of obj
Canvas.SetZIndex((UIElement)VisualTreeHelper.GetParent(obj), (int)e.NewValue);
}
}
In your DataTemplate you may now bind the helper property to one of your VM properties, perhaps by using an appropriate binding converter:
<DataTemplate x:Key="MapItemDataTemplate">
<!-- setting the helper property MapItem.ZIndex on Canvas
sets the Canvas.ZIndex property on the item container -->
<Canvas local:MapItem.ZIndex="{Binding ...}">
...
</Canvas>
</DataTemplate>
In a Tabbed interface application i'm trying to pass the TabItem Header string or the object contained in the selected TabItem to the view model to use it to
publish an event like this:
In the View (xaml):
<TabControl x:Name="MyTC"
prism:RegionManager.RegionName="{x:Static inf:RegionNames.MainRegion}"
SelectedItem="{Binding Path=TabControlSelectedItem,UpdateSourceTrigger=PropertyChanged,Mode=Twoway}"
Cursor="Hand"
Grid.Row="0"
Grid.Column="1">
<TabControl.ItemTemplate>
<DataTemplate>
<!--DataContext="{Binding ElementName=MyTC, Path=SelectedItem}"-->
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center"
Margin="3"
Text="{Binding Path=DataContext.DataContext.HeaderInfo, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabItem}}}"
/>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<i:InvokeCommandAction Command="{Binding HeaderClickCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
In View Model
//***********************************************************
//Constructor
public ShellWindowViewModel(IEventAggregator eventAggregator)
{
this.eventAggregator = eventAggregator;
this.HeaderClickCommand = new DelegateCommand(OnHeaderClick);
}
//SelectedItem Binding
private object tabControlSelectedItem;
public object TabControlSelectedItem
{
get { return tabControlSelectedItem; }
set
{
if (tabControlSelectedItem != value)
{
tabControlSelectedItem = value;
OnPropertyChanged("TabControlSelectedItem");
}
}
}
//*****************************************************************************************************
//this handler publish the Payload "SelectedSubsystem" for whoever subscribe to this event
private void OnHeaderClick()
{
//EA for communication between Modules not within Modules
string TabHeader = (TabControlSelectedItem as TabItem).Header.ToString();
eventAggregator.GetEvent<SubsystemIDSelectedEvent>().Publish(TabHeader);
}
but there is something wrong because when i click the TabItem nothing happen and when i inserted a breakpoint # TabControlSelectedItem
property i found it contain the view namespace.i want the TabControlSelectedItem to get the selected Tab header string or the object in
the selected tab item.
Your help is very much appreciated.
I just tried something similar and it works fine.
Here is my xaml
<TabControl ItemsSource="{Binding Matches}"
SelectedItem="{Binding SelectedRecipe}">
<TabControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Text="{Binding Path=Date}" />
<TextBlock Grid.Column="1"
TextAlignment="Center"
Text="{Binding Path=Name}" />
</Grid>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
And then in my viewmodel
public object SelectedRecipe
{
get
{
return _selectedRecipe;
}
set
{
_selectedRecipe = value;
OnNotifyPropertyChanged("SelectedRecipe");
}
}
I have created a Treeview and used a stack panel to include a checkbox, icon image and text for each node in the tree.
These nodes are created at runtime.
I also have a button object.
The xaml is below.
The problem i have is that, when the click me button is clicked, i need to traverse thru the tree view and if a checkbox is checked, perform some function.
Does anyone know how to find out if the checkbox for a node in the tree is checked, from the C# code behind ???
<Window x:Class="WPF_Explorer_Tree.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPF_Explorer_Tree"
Title="KryptoG" Height="424" Width="815" Loaded="Window_Loaded">
<Window.Resources>
<local:HeaderConverter x:Key="formatter" />
</Window.Resources>
<Grid>
<TreeView x:Name="foldersItem" SelectedItemChanged="foldersItem_SelectedItemChanged" Background="#FFFFFFFF" BorderBrush="#FFFFFFFF" Foreground="#FFFFFFFF" Margin="0,0,236,112" AllowDrop="True" Visibility="Visible">
<TreeView.Resources>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Name="ST" Orientation="Horizontal">
<CheckBox VerticalAlignment="Center" Name="SelectedCheckBox" IsChecked="False" Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked" />
<Image Name="img" Width="20" Stretch="Fill"
Source="{Binding
RelativeSource={RelativeSource
Mode=FindAncestor,
AncestorType={x:Type TreeViewItem}},
Path=Header,
Converter={x:Static local:HeaderToImageConverter.InstanceIcon}}"
/>
<TextBlock VerticalAlignment="Center" Text="{Binding
RelativeSource={RelativeSource
Mode=FindAncestor,
AncestorType={x:Type TreeViewItem}},
Path=Header,
Converter={StaticResource formatter}}"
/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.Resources>
</TreeView>
<TreeView HorizontalAlignment="Right" Margin="0,0,12,12" Name="treeView1" Width="204" AllowDrop="True" BorderBrush="White" Foreground="White" />
<Button Height="23" HorizontalAlignment="Left" Margin="12,0,0,70" Name="button1" VerticalAlignment="Bottom" Width="75" Click="button1_Click">Click Me</Button>
<Button Height="23" HorizontalAlignment="Left" Margin="267,0,0,69" Name="button2" VerticalAlignment="Bottom" Width="75" Click="button2_Click">Click Me too</Button>
</Grid>
I would create a Two-Way data binding with that Check Box's IsChecked property to a ViewModel object instead. Much easier than navigating the tree.
Edit (per request of person asking):
Here's an example View Model (very simple that is only accounting for the IsChecked property):
public class ViewModel : System.ComponentModel.INotifyPropertyChanged
{
private bool? _isChecekd;
public bool? IsChecked
{
get { return _isChecekd; }
set
{
if (_isChecekd != value)
{
_isChecekd = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs("IsChecked"));
}
}
}
}
#region INotifyPropertyChanged Members
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
#endregion
}
Now that you have an object implementing INotifyPropertyChanged, you can bind UI element properties to them. So you would update the IsChecked property of your CheckBox to this property. To do that, you first have to set the DataContext of Window1 in some way (or you could just do this on the TreeView itself as well). In your Window1.xaml.cs:
public Window1()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
Then, in your Window1.xaml file, update the CheckBox IsChecked property:
<CheckBox VerticalAlignment="Center" Name="SelectedCheckBox" IsChecked="{Binding Path=IsChecked, Mode=TwoWay}" Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked" />
And then, in whatever code you need to be able to interrogate the currently value of IsChecked, you can get to it this way (assuming this is Window1):
((ViewModel)this.DataContext).IsChecked
Hope that helps!
I think Tony Heupel's answer is the best approach, but to understand it you need to know about the MVVM (Model-View-ViewModel) design pattern. I suggest you read this excellent article by Josh Smith