CheckBox not showing as a checked in UI - c#

Hello can any one please help me in my code,
i have xaml:
<ListView Name="__Listview" ItemsSource="{Binding Path=DisplayItems}">
<CheckBox Content="{Binding Items}" IsChecked="{Binding Path=IsChecked, Mode=TwoWay, NotifyOnTargetUpdated=True}" Checked="CheckBox_Checked" Unchecked="CheckBox_Checked"/>
</ListView>
<CheckBox Name="_checkBoxSelectAll" Checked="CheckBoxToCheckAll" Unchecked="CheckBoxToCheckAll"/>
Code C#:
public partial class DisplayItems
{
private ObservableCollection<Records> _displayItems = new ObservableCollection< Records>();
public DisplayItems ()
{
InitializeComponent();
_ Listview.DataContext = this;
}
public ObservableCollection< Records > DisplayItems
{
get { return _displayItems; }
set { _displayItems = value; }
}
private void CheckBoxToCheckAll(object sender, RoutedEventArgs e)
{
if (_checking || !(sender is CheckBox))
return;
CheckBox checkBox = (CheckBox)sender;
_checking = true;
foreach (Records swElement in DisplayItems)
{
bool val;
if (checkBox.IsChecked != null)
val = checkBox.IsChecked.Value;
else
val = false;
swElement.IsChecked = val;
}
_checking = false;
}
private void CheckBox_Checked(object sender, RoutedEventArgs e)
{
if ((sender as CheckBox) == null || ((sender as CheckBox).DataContext as Records) == null || _checking)
return;
_checking = true;
if (_checkBoxSelectAll.IsChecked != null && _listTo.All(select => select.IsChecked) && !_checkBoxSelectAll.IsChecked.Value)
_checkBoxSelectAll.IsChecked = true;
else if (_checkBoxSelectAll.IsChecked == null || _checkBoxSelectAll.IsChecked.Value)
_checkBoxSelectAll.IsChecked = false;
_checking = false;
}
}
Public class Records
{
public event PropertyChangedEventHandler PropertyChanged;
private bool _isChecked = false;
Public Records(){}
public bool IsChecked
{
get { return _isChecked; }
set { _isChecked = value; OnPropertyChanged("IsChecked"); }
}
protected void OnPropertyChanged(string name)
{
if ((PropertyChanged != null) && (_notification))
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
public enum Items{One,Two,three,}
}
if i Check _checkBoxSelectAll , All checkBoxs in Listview should check, my problem is code behind its IsChecked=true, but in UI not visible that Checkbox is checked, pleae help me in advance

Implement INotifyPropertyChanged on Records?
Public class Records**: INotifyPropertyChanged**
Replace your records class with below please
Public class Records : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool _isChecked = false;
Public Records(){}
public `bool IsChecked`
{
get { return _isChecked; }
set { _isChecked = value; OnPropertyChanged("IsChecked"); }
}
protected void OnPropertyChanged(string name)
{
if ((PropertyChanged != null) && (_notification))
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
public enum Items{One,Two,three,}
}

Related

TabControl Command binding

I am using this code following code taken from Stackoverflow.
I want to transfer a string from one view model to another one on SelectionChanged event. But when I click on Tab2, I get Tab2 message box, but when I click on Tab1, I get both the message boxes indicating that both are getting executed. The same when I click Tab1, both message boxes are seen.
MainView.xaml
<TabControl>
<TabItem Header="My tab 1" Selector.IsSelected="{Binding IsMyTab1Selected}"> ... </TabItem>
<TabItem Header="My tab 2" Selector.IsSelected="{Binding IsMyTab2Selected}"> ... </TabItem>
</TabControl>
MainViewModel.cs
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName) {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public MainViewModel() {
PropertyChanged += handlePropertyChanged;
}
public bool IsMyTab1Selected {
get { return _IsMyTab1Selected ; }
set {
if (value != _IsMyTab1Selected ) {
_IsMyTab1Selected = value;
OnPropertyChanged("IsMyTab1Selected ");
}
}
}
private bool _IsMyTab1Selected = false;
public bool IsMyTab2Selected {
get { return _IsMyTab2Selected ; }
set {
if (value != _IsMyTab2Selected ) {
_IsMyTab2Selected = value;
OnPropertyChanged("IsMyTab2Selected ");
}
}
}
private bool _IsMyTab2Selected = false;
private void handlePropertyChanged(object sender, PropertyChangedEventArgs e) {
if (e.PropertyName == "IsMyTab1Selected") {
MessageBox.Show("Tab_1 Clicked!");
} else if (e.PropertyName == "IsMyTab2Selected") {
MessageBox.Show("Tab_2 Clicked!");
}
}
I am not able to get the mutually exclusiveness, point me where I am wrong.
Option 1
you can change the setters to only call OnPropertyChanged(..) when the value is true:
public bool IsMyTab1Selected
{
get { return _IsMyTab1Selected; }
set
{
if (value != _IsMyTab1Selected)
{
_IsMyTab1Selected = value;
if (_IsMyTab1Selected)
OnPropertyChanged("IsMyTab1Selected");
}
}
}
public bool IsMyTab2Selected
{
get { return _IsMyTab2Selected; }
set
{
if (value != _IsMyTab2Selected)
{
_IsMyTab2Selected = value;
if(_IsMyTab2Selected)
OnPropertyChanged("IsMyTab2Selected");
}
}
}
Option 2
Or you can check in your handlePropertyChange() if the value is true like this
private void handlePropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "IsMyTab1Selected")
{
if(IsMyTab1Selected)
MessageBox.Show("Tab_1 Clicked!");
}
else if (e.PropertyName == "IsMyTab2Selected")
{
if(IsMyTab2Selected)
MessageBox.Show("Tab_2 Clicked!");
}
}
The bindings will update on deselection too. You need to check e.NewValue in your handler, or why not simply check _IsMyTab1Selected etc?

WPF ComboBox Not updating on propertychanged event

I have a custom combobox in my WPF application and the combo box is not updating when my item source is updated after initial launch. The itemsSource is a custom observableDictionary. I've implemented INotifyPropertyChanged on my properties with my observableDictionary but it won't update. I've searched through every WPF propertychanged event not working on stack overflow and i'm looking for some assistance.
Custom Combobox Code:
<controls:MultiSelectComboBox Width="100" Height="30" Padding="0 10 0 0" Grid.Row="0" Grid.Column="1"
ItemsSource="{Binding Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged,
ValidatesOnDataErrors=True,
Path=DataContext.OptionTeamMembersDictionary,
BindsDirectlyToSource=True,
RelativeSource={RelativeSource AncestorType={x:Type UserControl},Mode=FindAncestor}}"
SelectedItems="{Binding SelectedOptionTeamMembersDictionary, Mode=TwoWay}"
x:Name="TeamMemberDisplay"
ToolTip="{Binding Path=Text, RelativeSource={RelativeSource Self}}"/>
Properties and private variables:
private ObservableDictionary<string, object> _optionTeamMembersDictionary;
private ObservableDictionary<string, object> _selectedOptionTeamMembersDictionary;
public ObservableDictionary<string, object> OptionTeamMembersDictionary
{
get
{
return _optionTeamMembersDictionary;
}
set
{
_optionTeamMembersDictionary = value;
OnPropertyChanged("OptionTeamMembersDictionary");
}
}
public ObservableDictionary<string, object> SelectedOptionTeamMembersDictionary
{
get
{
return _selectedOptionTeamMembersDictionary;
}
set
{
_selectedOptionTeamMembersDictionary = value;
OnPropertyChanged("SelectedOptionTeamMembersDictionary");
}
}
I use a button to trigger a database pull which leads each row into an object and then populates the optionTeamMemberDictionary when it returns more then one row of data.
All of the above works when the data is loaded in my constructor but when its loaded after launch my comboboxes do not show the new data in the collection.
EDIT:
Code for the Custom ComboBox being used:
https://www.codeproject.com/Articles/563862/Multi-Select-ComboBox-in-WPF is the URL this came from. Some edits were made to implement an obserableDirctionary instead of normal dictionary
public partial class MultiSelectComboBox : UserControl
{
private ObservableCollection<Node> _nodeList;
public MultiSelectComboBox()
{
InitializeComponent();
_nodeList = new ObservableCollection<Node>();
}
#region Dependency Properties
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(ObservableDictionary<string, object>), typeof(MultiSelectComboBox), new FrameworkPropertyMetadata(null,
new PropertyChangedCallback(MultiSelectComboBox.OnItemsSourceChanged)));
public static readonly DependencyProperty SelectedItemsProperty =
DependencyProperty.Register("SelectedItems", typeof(ObservableDictionary<string, object>), typeof(MultiSelectComboBox), new FrameworkPropertyMetadata(null,
new PropertyChangedCallback(MultiSelectComboBox.OnSelectedItemsChanged)));
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(MultiSelectComboBox), new UIPropertyMetadata(string.Empty));
public static readonly DependencyProperty DefaultTextProperty =
DependencyProperty.Register("DefaultText", typeof(string), typeof(MultiSelectComboBox), new UIPropertyMetadata(string.Empty));
public ObservableDictionary<string, object> ItemsSource
{
get { return (ObservableDictionary<string, object>)GetValue(ItemsSourceProperty); }
set
{
SetValue(ItemsSourceProperty, value);
}
}
public ObservableDictionary<string, object> SelectedItems
{
get { return (ObservableDictionary<string, object>)GetValue(SelectedItemsProperty); }
set
{
SetValue(SelectedItemsProperty, value);
}
}
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public string DefaultText
{
get { return (string)GetValue(DefaultTextProperty); }
set { SetValue(DefaultTextProperty, value); }
}
#endregion
#region Events
private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MultiSelectComboBox control = (MultiSelectComboBox)d;
control.DisplayInControl();
}
private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MultiSelectComboBox control = (MultiSelectComboBox)d;
control.SelectNodes();
control.SetText();
}
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
CheckBox clickedBox = (CheckBox)sender;
if (clickedBox.Content == "All")
{
if (clickedBox.IsChecked.Value)
{
foreach (Node node in _nodeList)
{
node.IsSelected = true;
}
}
else
{
foreach (Node node in _nodeList)
{
node.IsSelected = false;
}
}
}
else
{
int _selectedCount = 0;
foreach (Node s in _nodeList)
{
if (s.IsSelected && s.Title != "All")
_selectedCount++;
}
if (_selectedCount == _nodeList.Count - 1)
_nodeList.FirstOrDefault(i => i.Title == "All").IsSelected = true;
else
_nodeList.FirstOrDefault(i => i.Title == "All").IsSelected = false;
}
SetSelectedItems();
SetText();
}
#endregion
#region Methods
private void SelectNodes()
{
foreach (KeyValuePair<string, object> keyValue in SelectedItems)
{
Node node = _nodeList.FirstOrDefault(i => i.Title == keyValue.Key);
if (node != null)
node.IsSelected = true;
}
}
private void SetSelectedItems()
{
if (SelectedItems == null)
SelectedItems = new ObservableDictionary<string, object>();
SelectedItems.Clear();
foreach (Node node in _nodeList)
{
if (node.IsSelected && node.Title != "All")
{
if (this.ItemsSource.Count > 0)
SelectedItems.Add(node.Title, this.ItemsSource[node.Title]);
}
}
}
private void DisplayInControl()
{
_nodeList.Clear();
if (this.ItemsSource.Count > 0)
_nodeList.Add(new Node("All"));
foreach (KeyValuePair<string, object> keyValue in this.ItemsSource)
{
Node node = new Node(keyValue.Key);
_nodeList.Add(node);
}
MultiSelectCombo.ItemsSource = _nodeList;
}
private void SetText()
{
if (this.SelectedItems != null)
{
StringBuilder displayText = new StringBuilder();
foreach (Node s in _nodeList)
{
if (s.IsSelected == true && s.Title == "All")
{
displayText = new StringBuilder();
displayText.Append("All");
break;
}
else if (s.IsSelected == true && s.Title != "All")
{
displayText.Append(s.Title);
displayText.Append(',');
}
}
this.Text = displayText.ToString().TrimEnd(new char[] { ',' });
}
// set DefaultText if nothing else selected
if (string.IsNullOrEmpty(this.Text))
{
this.Text = this.DefaultText;
}
}
#endregion
}
public class Node : INotifyPropertyChanged
{
private string _title;
private bool _isSelected;
#region ctor
public Node(string title)
{
Title = title;
}
#endregion
#region Properties
public string Title
{
get
{
return _title;
}
set
{
_title = value;
NotifyPropertyChanged("Title");
}
}
public bool IsSelected
{
get
{
return _isSelected;
}
set
{
_isSelected = value;
NotifyPropertyChanged("IsSelected");
}
}
#endregion
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
After much troubleshooting i was able to figure out an answer for this. onItemsSourceChanged was not firing after the control was instantiated so it never got updates made after initial launch of the application. I edited the OnItemsSourceChanged Function on the MultiFunctionComboBox to the below so it would fire on a changed event and it is working as expected now.
private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MultiSelectComboBox control = (MultiSelectComboBox)d;
var action = new NotifyCollectionChangedEventHandler(
(o, args) =>
{
MultiSelectComboBox c = (MultiSelectComboBox)d;
c?.DisplayInControl();
});
if (e.OldValue != null)
{
var sourceCollection = (ObservableDictionary<string, object>)e.OldValue;
sourceCollection.CollectionChanged -= action;
}
if (e.NewValue != null)
{
var sourceCollection = (ObservableDictionary<string, object>)e.NewValue;
sourceCollection.CollectionChanged += action;
}
control.DisplayInControl();
}

Why can't I reflect a list box choice in a text box in WPF?

I'm new to WPF and I'm having some trouble with my existing setup to get the list box selected item to appear in the text box.
The picture here represents the issue. I typed "12 HOUR" in the text box, which then filters the listbox to those items with "12 HOUR" anywhere in the string. But when I click "12 Hour Nasal" in the list box, I now want to reflect that choice back in the text box:
http://i.imgur.com/ZCYAolT.png
Here is my XAML for the user control containing the listbox and textbox:
<UserControl x:Class="SCM_AllergyRecModule.SearchAndSelectView"
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"
mc:Ignorable="d">
<StackPanel Width="300">
<TextBox x:Name="Filter" Text="{Binding Path=Filter, UpdateSourceTrigger=PropertyChanged}"/>
<ListBox Width ="300" Height="50" x:Name="ListBoxControl"
ItemsSource="{Binding Path=Allergens}"
SelectedItem="{Binding Path=SelectedAllergen}">
</ListBox>
</StackPanel>
And here is the ViewModel:
namespace SCM_AllergyRecModule
{
public class SearchAndSelectViewModel
{
private ICollectionView allergens;
private string selectedAllergen;
private string filter = "";
public string Filter
{
get
{
return this.filter.ToUpperInvariant();
}
set
{
if (this.filter != value)
{
this.filter = value;
this.Allergens.Refresh();
}
}
}
private bool ContainsFilter(object item)
{
var product = item as string;
if (product == null)
{
return false;
}
if (string.IsNullOrEmpty(this.Filter))
{
return true;
}
if (product.ToUpperInvariant().Contains(this.Filter))
{
return true;
}
return false;
}
public SearchAndSelectViewModel()
{
var cvs = new CollectionViewSource();
cvs.Source = MainWindow.scmAllergens;
this.allergens = cvs.View;
this.allergens.Filter = ContainsFilter;
}
public ICollectionView Allergens
{
get
{
return this.allergens;
}
}
public string SelectedAllergen
{
get
{
return this.selectedAllergen;
}
set
{
if (this.selectedAllergen != value)
{
this.selectedAllergen = value;
}
}
}
}
}
Update 1
I added the INotifyPropertyChanged interface to my class and have it being raised on SelectedAllergen in the setter. I added an event handler called SearchAndSelectViewModel_PropertyChanged to handle the SelectedAllergen property changing and set it in the constructor.
Now when I click an item in the listbox, I do see it setting the Filter to the SelectedItem and the list filters to that item so nothing else shows. But still, the text box text is not changing? See screenshot below. This is after I typed in "PEAN" in the textbox, then the listbox filtered to two choices, and I chose "PEANUTS (FOOD)", which then refiltered the list box to just show that choice but didn't set the text box to "PEANUTS (FOOD)":
http://imgur.com/dNxuVI5
Updated ViewModel
public class SearchAndSelectViewModel : INotifyPropertyChanged
{
private ICollectionView allergens;
private string selectedAllergen;
private string filter;
public string Filter
{
get
{
return this.filter.ToUpperInvariant();
}
set
{
if (this.filter != value)
{
this.filter = value;
this.Allergens.Refresh();
}
}
}
private bool ContainsFilter(object item)
{
var product = item as string;
if (product == null)
{
return false;
}
if (string.IsNullOrEmpty(this.Filter))
{
return true;
}
if (product.ToUpperInvariant().Contains(this.Filter))
{
return true;
}
return false;
}
private void SearchAndSelectViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "SelectedAllergen":
this.Filter = this.SelectedAllergen;
break;
}
}
public SearchAndSelectViewModel()
{
filter = "";
var cvs = new CollectionViewSource();
cvs.Source = MainWindow.scmAllergens;
this.allergens = cvs.View;
this.allergens.Filter = ContainsFilter;
this.PropertyChanged += SearchAndSelectViewModel_PropertyChanged;
}
public ICollectionView Allergens
{
get
{
return this.allergens;
}
}
public string SelectedAllergen
{
get
{
return this.selectedAllergen;
}
set
{
if (this.selectedAllergen != value && value != null)
{
this.selectedAllergen = value;
OnPropertyChanged("SelectedAllergen");
}
}
}
// INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
You need to implement the INotifyPropertyChanged interface and you can raise it in your property setter. Since you are also binding your TextBox to the Filter property you need to set the Filter property when your SelectedAllergen changes.
INotifyPropertyChanged example:
public class MyViewModel : INotifyPropertyChanged
{
//...
private int myProperty = 0;
public int MyProperty
{
get { return myProperty; }
set
{
myProperty = value;
// Raise the property changed notification
OnPropertyChanged("MyProperty");
}
}
// INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if(handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}

Why is my XAML not responding to a change in a variable

there is probably a really simple reason why this isnt working but I've tried everything. I have a TextBlock with Text bound to a variable, the variable changes but the Text doesn't :
<TextBlock x:Name="modeLabel" Style="{StaticResource IndiTextBlock}" Height="23" TextWrapping="Wrap" Grid.Row="0" Text="{Binding ModeLabelText}" Margin="35,22,58,0"/>
The code that controls the text value is in a viewmodel:
public string ModeLabelText { get { return _modeLabeltext; } }
public ComboBoxItem SelectedMode { get { return _selectedMode; }
set
{
if (_selectedMode == value) return;
_selectedMode = value;
ToggleMode(null);
EvaluateScenario(null);
}
and
private void ToggleMode(object parameter)
{
if (_isBasicCalculation)
{
_modeLabeltext = "Target profit";
_isBasicCalculation = false;
}
else
{
_modeLabeltext = "Total to invest";
_isBasicCalculation = true;
}
}
Your class has to implement the INotifyPropertyChanged interface, and on changes of your variables, you should trigger the event
public class Model : INotifyPropertyChanged
{
public event EventHandler PropertyChanged; // event from INotifyPropertyChanged
protected void RaisePropertyChanged(string propertyName)
{
var local = PropertyChanged;
if (local != null)
{
local.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public void ToggleMode()
{
// ... your code ...
RaisePropertyChanged("ModelLabelText");
}
}
Thank you Nguyen Kien
private void ToggleMode(object parameter)
{
if (_isBasicCalculation)
{
_modeLabeltext = "Target profit";
OnPropertyChanged("ModeLabelText");
_isBasicCalculation = false;
}
else
{
_modeLabeltext = "Total to invest";
OnPropertyChanged("ModeLabelText");
_isBasicCalculation = true;
}
}

Can not find child control on ItemContainerGenerator?

I'm using ItemsControl for StackPanel as below code:
File playBackControl.xaml - Begin
<ScrollViewer x:Name="scrollViewerChannelBtns">
<StackPanel x:Name="channelBtns" Orientation="Vertical" MouseWheel="ScrollViewer_MouseWheel">
<ItemsControl x:Name="channelBtnItems" ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ToogleButton x:Name="tgbChannelName"
HorizontalAlignment="Center" VerticalAlignment="Center"
Width="{Binding Path=ChannelNameBtnWidth}"
Height="{Binding Path=ChannelNameBtnHeight}"
Margin="{Binding Path=ChannelNameBtnMargin}"
IsChecked="{Binding Path=IsChecked, Mode=TwoWay}"
ToolTip="{Binding Path=ToolTip}" Tag="{Binding Path=Index}"
IsEnabled="{Binding Path=IsEnabled}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
File playBackControl.xaml - End
File playBackControl.xaml.cs - Begin
public partial class PlayBackControl : UserControl
{
public static List<ChannelBtnItemData> listChannelBtnItemData = new List<ChannelBtnItemData>();
public PlayBackControl() //This will run first when the app start
{
InitializeComponent();
channelBtnItems.ItemContainerGenerator.StatusChanged += ChannelBtnItemsStatusChangedEventHandler;
System.Threading.Thread threadTimer = new System.Threading.Thread(TimerThreadThreadProc);
threadTimer.Start();
}
private void TimerThreadThreadProc()
{
while (true)
{
Thread.Sleep(60000); //Sleep 60s
this.Dispatcher.BeginInvoke(new Action(delegate()
{
//Re init listChannelBtnItemData, this list has about 64 items
channelBtnItems.ItemsSource = listChannelBtnItemData;
channelBtnItems.Items.Refresh();
}));
}
}
public class ChannelBtnItemData : INotifyPropertyChanged
{
private String _toolTip;
private int _index;
private int _channelID;
private bool _isChecked;
private bool _isEnabled;
private bool _lockToggle;
private double _channelNameBtnWidth;
private double _channelNameBtnHeight;
private Thickness _channelNameBtnMargin;
public String ToolTip
{
get { return _toolTip; }
set
{
_toolTip = value;
OnPropertyChanged("ToolTip");
}
}
public int Index
{
get { return _index; }
set
{
_index = value;
OnPropertyChanged("Index");
}
}
public int ChannelID
{
get { return _channelID; }
set
{
_channelID = value;
OnPropertyChanged("ChannelID");
}
}
public bool IsChecked
{
get { return _isChecked; }
set
{
_isChecked = value;
OnPropertyChanged("IsChecked");
}
}
public bool IsEnabled
{
get { return _isEnabled; }
set
{
_isEnabled = value;
OnPropertyChanged("IsEnabled");
}
}
public bool LockToggle
{
get { return _lockToggle; }
set
{
_lockToggle = value;
OnPropertyChanged("LockToggle");
}
}
public double ChannelNameBtnWidth
{
get { return _channelNameBtnWidth; }
set
{
_channelNameBtnWidth = value;
OnPropertyChanged("ChannelNameBtnWidth");
}
}
public double ChannelNameBtnHeight
{
get { return _channelNameBtnHeight; }
set
{
_channelNameBtnHeight = value;
OnPropertyChanged("ChannelNameBtnHeight");
}
}
public Thickness ChannelNameBtnMargin
{
get { return _channelNameBtnMargin; }
set
{
_channelNameBtnMargin = value;
OnPropertyChanged("ChannelNameBtnMargin");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
public ChannelBtnItemData()
{
}
}
private void ChannelBtnItemsStatusChangedEventHandler(Object sender, EventArgs e)
{
if (channelBtnItems.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
{
if (channelBtnItems.HasItems)
{
var containers = channelBtnItems.Items.Cast<Object>().Select(
item => (FrameworkElement)channelBtnItems.ItemContainerGenerator.ContainerFromItem(item));
foreach (var container in containers)
{
if (container != null)
container.Loaded += ChannelBtnItemContainerLoaded;
}
}
}
}
private void ChannelBtnItemContainerLoaded(object sender, RoutedEventArgs e)
{
var element = (FrameworkElement)sender;
element.Loaded -= ChannelBtnItemContainerLoaded;
ToogleButton tgbChannelName = FindChild<ToogleButton>(element, "tgbChannelName");
if (tgbChannelName != null) //Sometimes It equal null
{
//Do something
}
}
public T FindChild<T>(DependencyObject parent, string childName)
where T : DependencyObject
{
// Confirm parent and childName are valid.
if (parent == null) return null;
T foundChild = null;
int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
// If the child is not of the request child type child
T childType = child as T;
if (childType == null)
{
// recursively drill down the tree
foundChild = FindChild<T>(child, childName);
// If the child is found, break so we do not overwrite the found child.
if (foundChild != null) break;
}
else if (!string.IsNullOrEmpty(childName))
{
var frameworkElement = child as FrameworkElement;
// If the child's name is set for search
if (frameworkElement != null && frameworkElement.Name == childName)
{
// if the child's name is of the request name
foundChild = (T)child;
break;
}
else
{
// recursively drill down the tree
foundChild = FindChild<T>(child, childName);
// If the child is found, break so we do not overwrite the found child.
if (foundChild != null) break;
}
}
else
{
// child element found.
foundChild = (T)child;
break;
}
}
return foundChild;
}
}
File playBackControl.xaml.cs - End
In the ChannelBtnItemContainerLoaded() function, sometimes the tgbChannelName equal null,
I have searched and read more about this, but I don't know how to fix it.
I create a demo to test this but it worked for me. Loaded event is being fired when all is there available to access and so I never ran into the state where instance was null.
However I have a feeling that you haven't revealed us what you exactly up to there.
Are you changing the ItemsSource at runtime? At what point do you swap the ItemsSource?
Where is the following code of yours being called?
channelBtnItems.ItemContainerGenerator.StatusChanged += ChannelBtnItemsStatusChangedEventHandler;
channelBtnItems.ItemsSource = listChannelBtnItemData;
channelBtnItems.Items.Refresh();
However here is a trick how you can "postpone" an action.
Use the Dispatcher.BeginInvoke with DispatcherPrority.Background.
http://weblogs.asp.net/pawanmishra/archive/2010/06/06/understanding-dispatcher-in-wpf.aspx
private void ChannelBtnItemContainerLoaded(object sender, RoutedEventArgs e)
{
var element = (FrameworkElement)sender;
element.Loaded -= ChannelBtnItemContainerLoaded;
element.Dispatcher.BeginInvoke((Action)(() =>
{
ToggleButton tgbChannelName = FindChild<ToggleButton>(element, "tgbChannelName");
if (tgbChannelName != null) //Sometimes It equal null
{
//Do something
}
else
{
}
}), DispatcherPriority.Background);
}
Try it out. If this doesnt help please provide us with the complete code including data and viewmodel so can test on same code just like yours.

Categories