What I need to do is stop GridSplitter before going far beyond and thus hiding the TabControl. So the idea that hit upon my mind is to Bind the sum of ActualWidths of all Headers of TabItems to the MinWidth of TabControl or the Crid Cell keeping the TabControl. But the problem is I am unable to access the Width of Header of TabItem so far. One solution I found was place a TextBlock inside Tabitem.Header, declare its width and name it with x:Name. But using the width this way doesn't gives the total Width of the Header the includes margins and paddings etc, thus it doesn't work even near to accuracy.
UPDATE
Well, here is the code. Note that I have implemented one of the solutions but it does not control the MinWidth if tabs were loaded dynamically.
<Grid Background="#FFD6DBE9" Height="614" Width="1109">
<Grid.RowDefinitions>
<RowDefinition Height="89"/>
<RowDefinition Height="Auto" MinHeight="{Binding ActualHeight, ElementName=gridNotificationsHeader}"/>
<RowDefinition Height="494*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="400*" MinWidth="{Binding MinWidth, ElementName=tabDataEntities}"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="144*">
<ColumnDefinition.MinWidth>
<MultiBinding Converter="{StaticResource StringSumtoIntConvert}">
<Binding ElementName="cdLblNotificationsHeader" Path="MinWidth"/>
<Binding ElementName="cdBtnNotificationsClose" Path="ActualWidth"/>
</MultiBinding>
</ColumnDefinition.MinWidth>
</ColumnDefinition>
</Grid.ColumnDefinitions>
<GridSplitter x:Name="gridSplitter" Grid.Column="1" HorizontalAlignment="Center" Grid.Row="1" Width="2" Grid.RowSpan="2"/>
<Grid x:Name="gridNotificationsHeader" Grid.Column="2" Background="#FF657695"
Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="cdLblNotificationsHeader" MinWidth="{Binding Width, ElementName=lblNotificationsHeader}"/>
<ColumnDefinition x:Name="cdBtnNotificationsClose" Width="Auto"/>
</Grid.ColumnDefinitions>
<Label x:Name="lblNotificationsHeader" Content="Notifications" VerticalAlignment="Top"
FontSize="14.667" Height="30" Foreground="#FFEBF0EE" HorizontalAlignment="Left" Width="92"/>
<Button x:Name="btnNotificationsClose" Content="X"
Margin="0,5,8,0" VerticalAlignment="Top" Width="20" FontFamily="Verdana" HorizontalAlignment="Right" Background="Transparent" FontSize="13.333" Foreground="Black" Grid.Column="1"/>
</Grid>
<TabControl x:Name="tabDataEntities" Margin="0,0,5,10" Grid.Row="1" Grid.RowSpan="2" FontSize="12" Grid.ColumnSpan="1" MinWidth="{Binding ElementName=TabItemOne, Path=ActualWidth}">
<TabItem x:Name="TabItemOne">
<TabItem.Header>Tab Item</TabItem.Header>
<Grid Background="#FFE5E5E5"/>
</TabItem>
<TabItem Header="TabItem">
<Grid Background="#FFE5E5E5"/>
</TabItem>
</TabControl>
</Grid>
As simple as that
<StackPanel>
<TabControl>
<TabItem Header="Hello world" Name="Tab1"/>
<TabItem Header="Hello" Name="Tab2"/>
<TabItem Header="world" Name="Tab3"/>
</TabControl>
<TextBlock Text="{Binding ElementName=Tab1, Path=ActualWidth}"/>
<TextBlock Text="{Binding ElementName=Tab2, Path=ActualWidth}"/>
<TextBlock Text="{Binding ElementName=Tab3, Path=ActualWidth}"/>
</StackPanel>
Just had a little fun doing the following AttachedProperty:
XAML Usage
<TabControl question32926699:TabControlHeaderWidthWatcher.WatchHeadersWidth="true"
question32926699:TabControlHeaderWidthWatcher.TotalHeadersWidth="{Binding TotalWidth, Mode=OneWayToSource}">
<TabItem Header="Tab Item 1" />
<TabItem Header="Tab Item 2" />
</TabControl>
The attached property
public class TabControlHeaderWidthWatcher
{
private static TabControl m_tabControl;
public static readonly DependencyProperty WatchHeadersWidthProperty = DependencyProperty.RegisterAttached(
"WatchHeadersWidth", typeof (bool), typeof (TabControlHeaderWidthWatcher), new PropertyMetadata(default(bool), PropertyChangedCallback));
public static void SetWatchHeadersWidth(DependencyObject element, bool value)
{
element.SetValue(WatchHeadersWidthProperty, value);
}
public static bool GetWatchHeadersWidth(DependencyObject element)
{
return (bool)element.GetValue(WatchHeadersWidthProperty);
}
public static readonly DependencyProperty TotalHeadersWidthProperty = DependencyProperty.RegisterAttached(
"TotalHeadersWidth", typeof (double), typeof (TabControlHeaderWidthWatcher), new PropertyMetadata(default(double)));
public static void SetTotalHeadersWidth(DependencyObject element, double value)
{
element.SetValue(TotalHeadersWidthProperty, value);
}
public static double GetTotalHeadersWidth(DependencyObject element)
{
return (double) element.GetValue(TotalHeadersWidthProperty);
}
private static void PropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
m_tabControl = dependencyObject as TabControl;
if (m_tabControl == null) return;
((INotifyCollectionChanged)m_tabControl.Items).CollectionChanged += CollectionChanged;
}
private static void CollectionChanged(object sender, EventArgs eventArgs)
{
foreach (var item in m_tabControl.Items)
{
var tabItem = item as TabItem;
if (tabItem == null) continue;
// Unsubscribe first in case it was there previously
tabItem.SizeChanged -= TabItemOnSizeChanged;
tabItem.SizeChanged += TabItemOnSizeChanged;
}
}
private static void TabItemOnSizeChanged(object sender, SizeChangedEventArgs sizeChangedEventArgs)
{
var totalWidth = 0.0;
foreach (var item in m_tabControl.Items)
{
var tabItem = item as TabItem;
if (tabItem == null) continue;
totalWidth += tabItem.ActualWidth;
}
// When more than one row of tabs, the width of the TabControl is used
var actualWidth = totalWidth > m_tabControl.ActualWidth ? m_tabControl.ActualWidth : totalWidth;
SetTotalHeadersWidth(m_tabControl, actualWidth);
}
}
This solution will work even if you load Tabs dynamically using the ItemsSource of the TabControl. The TotalHeadersWidth will always receive the total headers width unless the tabs are wrapped in multiple rows. In that case, it will use the ActualWidth of the TabControl itself which in your case, gives what we want.
Related
I am trying to make textbox with autocomplete drop-down listbox.
The problem lies in that there is not space for listbox, as there are other items just below the textbox. Although, not seen on screenshot, the space between textbox and button will be filled with table.
Is there a way to dock or align a listbox to the bottom of given textbox, regardless to other items in layout?
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="70"/>
<RowDefinition Height="*"/>
<RowDefinition Height="70"/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0" x:Name="txtb_name"></TextBox>
<Grid Grid.Row="2" VerticalAlignment="Bottom">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" x:Name="btn_givecancel" Content="Cancel" Height="70" FontSize="18.667" Click="btn_givecancel_Click"/>
<Button Grid.Column="1" x:Name="btn_giveaccept" Content="Accept" Height="70" FontSize="18.667" Click="btn_giveaccept_Click"/>
</Grid>
</Grid>
Here's My Implementation:
Have a Converter that takes Total possible auto suggest item count and current view count:
<local:IntToVisibilityConverter x:Key="IntToVisibilityConverter"/>
Then here's is the Form with TextBox, ListBox and the Button controls.
<Grid Margin="50">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Text="{Binding UserText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" DockPanel.Dock="Top"/>
<ListBox Grid.Row="1" Grid.RowSpan="2" VerticalAlignment="Top" MaxHeight="55" ItemsSource="{Binding SuggestionsFiltered, UpdateSourceTrigger=PropertyChanged}"
Canvas.ZIndex="1">
<ListBox.Visibility>
<MultiBinding Converter="{StaticResource IntToVisibilityConverter}">
<Binding Path="MaxCount"/>
<Binding Path="SuggestionsFiltered.Count"/>
</MultiBinding>
</ListBox.Visibility>
</ListBox>
<StackPanel Grid.Row="2" Orientation="Horizontal" Margin="0 50 0 0">
<Button Height="20" Width="100">Clear</Button>
<Button Height="20" Width="100" Margin="10 0 0 0">Accept</Button>
</StackPanel>
</Grid>
Finally, here's my DataContext:
public class TheDataContext
{
public TheDataContext()
{
FillData();
_SuggestionsFiltered = CollectionViewSource.GetDefaultView(_SuggestionSource);
_SuggestionsFiltered.Filter = obj =>
{
var opt = obj as string;
if (string.IsNullOrEmpty(_UserText) || _UserText.Length == 0)
return true;
return string.Join("", opt.Take(_UserText.Length)) == _UserText;
};
}
private void FillData()
{
_SuggestionSource = new List<string>();
_SuggestionSource.Add("Alpha");
_SuggestionSource.Add("Alpines");
_SuggestionSource.Add("Bravo");
_SuggestionSource.Add("Brood");
_SuggestionSource.Add("Charlie");
_SuggestionSource.Add("Charles");
_SuggestionSource.Add("Charlotte");
}
private string _UserText;
public string UserText
{
get => _UserText;
set
{
_UserText = value;
_SuggestionsFiltered.Refresh();
}
}
private List<string> _SuggestionSource;
public int MaxCount => _SuggestionSource.Count;
private ICollectionView _SuggestionsFiltered;
public ICollectionView SuggestionsFiltered
{
get => _SuggestionsFiltered;
}
}
Notice all the code around ICollectionView. Also, I have forcefully set some margins in xaml to show case that Listbox is drawn over other controls (courtsey ZIndex).
If you take this code, remember to handle selected event on ListBox, then set the textBox Text to this value. Also hide the listbox. Bit of a jugglery there.
Lastly, here is the Converter, if you are interested:
public class IntToVisibilityConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
int maxCount = System.Convert.ToInt32(values[0]);
int count = System.Convert.ToInt32(values[1]);
if (count > 0 && count != maxCount)
return Visibility.Visible;
return Visibility.Collapsed;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
I would like to have a popup show at the bottom of each textbox in my window, as they are focused.
The user would be presented with the last few entries entered in that textbox. I would like the placement to be such that it would be at the bottom of the textbox currently focused.
This is my user control with the textbox:
<UserControl x:Class="PopupPlacement.MyControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<TextBox Name="TextBox_MyControl" Text="enter your text here" Height="25" Width="200"/>
</StackPanel>
</UserControl>
Here is my window:
<Window x:Class="PopupPlacement.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PopupPlacement"
Title="MainWindow" Height="450" Width="800">
<Canvas>
<Grid ShowGridLines="False">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Content="Domain" Margin="10"/>
<local:MyControl Grid.Column="1" x:Name="Domain" Margin="10"/>
<Label Grid.Row="1" Content="Username" Margin="10"/>
<local:MyControl Grid.Row="1" Grid.Column="1" x:Name="Username" Margin="10"/>
<Label Grid.Row="2" Content="Password" Margin="10"/>
<local:MyControl Grid.Row="2" Grid.Column="1" x:Name="Password" Margin="10"/>
<Button Grid.Row="3" Content="OK" Margin="10" Name="Button_OK"/>
<Button Grid.Row="3" Grid.Column="1" Content="Cancel" Margin="10"/>
<Popup PlacementTarget="{Binding ElementName=TextBox_MyControl}" Placement="Bottom"
IsOpen="{Binding ElementName=TextBox_MyControl, Path=IsKeyboardFocused}">
<ComboBox IsDropDownOpen="True">
<ComboBoxItem IsSelected="True">Item 1</ComboBoxItem>
<ComboBoxItem>Item 2</ComboBoxItem>
</ComboBox>
</Popup>
</Grid>
</Canvas>
</Window>
Appreciate any pointers.
For me, the best solution to a similar requirement was to write a Behavior that kind of mimics Intellisense.
I don't have any simple code at hand, but you could create and show a ListBox inside a Popup placed at the AssociatedObject's bottom. You can then bind the TextBox-related entries to the Behavior via a DependencyProperty.
Of course, there's a lot more to it like closing the Popup, re-using existing controls, handling key presses to access the ListBox, insert the selected value to the TextBox etc.
Here's a simple (untested) sketch.
public class IntellisenseBehavior : Behavior<TextBox>
{
public IEnumerable ItemsSource
{
get => (IEnumerable)GetValue(ItemsSourceProperty);
set => SetValue(ItemsSourceProperty, value);
}
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(IntellisenseBehavior), new UIPropertyMetadata(null));
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.GotKeyboardFocus += AssociatedObjectOnGotKeyboardFocus;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.GotKeyboardFocus -= AssociatedObjectOnGotKeyboardFocus;
//cleanup
}
private void AssociatedObjectOnGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
var popup = new Popup
{
ClipToBounds = false,
AllowsTransparency = true,
PopupAnimation = PopupAnimation.Fade,
HorizontalAlignment = HorizontalAlignment.Left
};
popup.SetValue(FocusManager.IsFocusScopeProperty, true);
popup.Placement = PlacementMode.Bottom;
popup.PlacementTarget = AssociatedObject;
var shadow = new SystemDropShadowChrome { Color = Colors.Transparent, MaxHeight = 200, Margin = new Thickness(0, 0, 5, 5) };
var listBox = new ListBox
{
ItemsSource = ItemsSource
}
((IAddChild)shadow).AddChild(listBox);
((IAddChild)popup).AddChild(shadow);
popup.IsOpen = true;
}
}
Attach it to all TextBoxes that you require to have this functionality and for instance use a converter to get the filtered entries you need.
<!-- Uses converter's public const string NameBox = "NameBox"; for filtering. -->
<TextBox>
<i:Interaction.Behaviors>
<IntellisenseBehavior ItemsSource="{Binding LastEntries, Converter={StaticResource FilterEntriesConverter}, ConverterParameter={x:Static FilterEntriesConverter.NameBox}}" />
</i:Interaction.Behaviors>
</TextBox>
Hope that helps.
I have this code:
<HubSection x:Name="MyHub">
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="200"></RowDefinition>
</Grid.RowDefinitions>
<Image x:Name="MYImage" Source="{Binding image}" Height="50" Width="60" VerticalAlignment="Center"/>
<StackPanel Orientation="Vertical">
<TextBlock TextWrapping="Wrap" Width="200" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{Binding name}"/>
<Button Content="Click me">
</StackPanel>
</Grid>
</DataTemplate>
</HubSection>
But I do not know how to access the text-block, I want to change the foreground color of the text-block in code behind.
XAML:
<Hub x:Name="myHub">
<HubSection x:Name="myHubSection">
<DataTemplate>
<TextBlock x:Name="textbox1" Text="text" Width="300" Height="100">
</TextBlock>
</DataTemplate>
</HubSection>
</Hub>
Code behind:
private void Page_Loaded(object sender, RoutedEventArgs e)
{
var hub_section = FindVisualChildByName<HubSection>(this.myHub, "myHubSection");
var text_box = FindVisualChildByName<WebView>(hub_section, "textbox1");
}
public static T FindVisualChildByName<T>(DependencyObject parent, string name)where T : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
string controlName = child.GetValue(Control.NameProperty) as string;
if (controlName == name)
{
return child as T;
}
else
{
T result = FindVisualChildByName<T>(child, name);
if (result != null)
return result;
}
}
return null;
}
More detailed information you could refer to How to access a Control inside the data template in C# Metro UI in the code behind
We are trying to bind Trigger on Stackpanel loaded while using RadMessageBox control. Example :
<!-- CustomMessageBox Template -->
<ControlTemplate x:Key="MessageBoxTemplate" TargetType="messageBox:RadMessageBoxControl">
<Border Padding="12" Background="{StaticResource PhoneChromeBrush}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ContentControl x:Name="PART_Title" Grid.Row="0"
HorizontalContentAlignment="Left"
FontSize="{StaticResource PhoneFontSizeLarge}"
FontFamily="{StaticResource PhoneFontFamilySemiBold}"
Margin="{StaticResource PhoneMargin}"/>
<ContentControl HorizontalContentAlignment="Left" Grid.Row="1"
VerticalContentAlignment="Top" Margin="{StaticResource PhoneMargin}"
x:Name="PART_Message"/>
<CheckBox x:Name="PART_CheckBox" Grid.Row="2"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"/>
<ContentControl x:Name="PART_ButtonsContainer" Grid.Row="3"
HorizontalContentAlignment="Stretch" Margin="12,0" Width="440">
<ContentControl.ContentTemplate>
<DataTemplate>
<StackPanel x:Name="PART_ButtonsPanel"
Orientation="Vertical" HorizontalAlignment="Stretch">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding DataContext.CustomMessageBoxStackPanelLoadedCommand}" CommandParameter="{Binding PART_ButtonsPanel}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</StackPanel>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</Grid>
</Border>
</ControlTemplate>
The ControlTemplate is inside Page.Resources.
We are unable to Trigger stackpanel loaded event. Code behind file :
private bool _CustomMessageBoxStackPanelLoadedCommandCanExecute = true;
bool CustomMessageBoxStackPanelLoadedCommandCanExecute
{
get
{
return _CustomMessageBoxStackPanelLoadedCommandCanExecute;
}
set
{
if (_CustomMessageBoxStackPanelLoadedCommandCanExecute == value)
{
return;
}
_CustomMessageBoxStackPanelLoadedCommandCanExecute = value;
RaisePropertyChanged("CustomMessageBoxStackPanelLoadedCommandCanExecute");
if (_CustomMessageBoxStackPanelLoadedCommand != null)
_CustomMessageBoxStackPanelLoadedCommand.RaiseCanExecuteChanged();
}
}
private RelayCommand<string> _CustomMessageBoxStackPanelLoadedCommand;
public ICommand CustomMessageBoxStackPanelLoadedCommand
{
get
{
if (_CustomMessageBoxStackPanelLoadedCommand == null)
{
_CustomMessageBoxStackPanelLoadedCommand = new RelayCommand<string>(CustomMessageBoxStackPanelLoaded, (data) => CustomMessageBoxStackPanelLoadedCommandCanExecute);
}
return _CustomMessageBoxStackPanelLoadedCommand;
}
}
private void CustomMessageBoxStackPanelLoaded(object obj)
{
System.Diagnostics.Debug.WriteLine("Hello");
}
The problem is with your CommandBinding. your binding is:
Command="{Binding DataContext.CustomMessageBoxStackPanelLoadedCommand}"
that means that in the DataContext class of your control there is any object name DataContext which has CustomMessageBoxStackPanelLoadedCommand as a property in it. But that is not the case. Such type of syntax is used in RelativeSource Binding.
But here change your binding as:
Command="{Binding CustomMessageBoxStackPanelLoadedCommand}"
So binding engine will now find this command directly inside your DataContext. (I hope there is not any problem with giving datacontext to your views.)
also not sure why you have written
CommandParameter="{Binding PART_ButtonsPanel}"
like this. what are you trying to do there?
I have this List box:
Here is the Code for my ListBox:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<ListBox x:Name="List" Grid.Row="0" ItemsSource="{Binding ShoppingItems}" FontSize="42" FontWeight="Light" FontFamily="Segoe WP Light" HorizontalContentAlignment="Stretch" ScrollViewer.HorizontalScrollBarVisibility="Visible">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" Margin="0,-15,0,22">
<Checkbox x:Name="MyCheckBox" IsChecked="{Binding IsChecked,Mode=TwoWay}"/>
</Grid>
<Grid x:Name="MyGrid" Margin="0,-15,0,22" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="{Binding DisplayingItem}" FontSize="46" Grid.Column="0" Grid.Row="0" TextWrapping="Wrap" />
<TextBlock Text="quantity" FontSize="32" Grid.Row="1" Margin="6,0,0,0" Grid.Column="0" TextWrapping="Wrap"/>
<TextBlock Text="{Binding DisplayingQuantity}" FontSize="32" Grid.Column="1" Grid.Row="1" Margin="32,0,12,12" TextWrapping="Wrap"/>
<TextBlock Grid.Column="2" Grid.Row="1" FontSize="32" Margin="32,0,12,12" Text="{Binding DisplayingPackaging}" TextWrapping="Wrap"/>
<TextBlock Text="price" Margin="6,0,0,0" FontSize="32" Grid.Row="2" Grid.Column="0" TextWrapping="Wrap"/>
<TextBlock Text="$" FontSize="32" Grid.Row="2" Grid.Column="1" Margin="32,0,12,12" TextWrapping="Wrap"/>
<TextBlock Grid.Column="3" FontSize="32" Grid.Row="2" Margin="32,0,12,12" Text="{Binding DisplayingPrice}" TextWrapping="Wrap"/>
</Grid>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
it has a checkbox inside, the ListBox is populated by data from a SQLite db. I want when I check the Checkbox to receive a message showing me the name of the SelectedItem of the ListBox.
Here is the Property for my CheckBox
private bool isChecked;
public bool IsChecked
{
get
{
if(this.SelectedItem != null)
{
return this.selectedItem.IsChecked;
}
return false;
}
set
{
this.isChecked = value;
}
}
When I check my Checkbox and Click This Button:
private void CheckedItem(object p)
{
if (this.IsChecked != false)
{
MessageBox.Show("Checked");
}
}
Nothing Happens.
I have included my Checkbox in my SelectedItem Like this:
private ShowingModel selectedItem;
public ShowingModel SelectedItem
{
get
{
return selectedItem;
}
set
{
if(this.selectedItem != value)
{
this.selectedItem = value;
if (this.selectedItem != null)
{
this.product = selectedItem.DisplayingItem;
this.price = selectedItem.DisplayingPrice;
this.qty = selectedItem.DisplayingQuantity;
this.package = selectedItem.DisplayingPackaging;
this.isChecked = selectedItem.IsChecked;
}
RaisePropertyChanged("MyPackage");
RaisePropertyChanged("MyPrice");
RaisePropertyChanged("MyProduct");
RaisePropertyChanged("MyQty");
RaisePropertyChanged("IsChecked");
}
}
}
So Where is the Problem.
Not an answer but too much for a comment
This is just messed up
You need to read up on data binding and start over
The following get and set don't refer to the same value
private bool isChecked;
public bool IsChecked
{
get
{
if(this.SelectedItem != null)
{
return this.selectedItem.IsChecked;
}
return false;
}
set
{
this.isChecked = value;
}
}
No indication SelectedItem is bound to anything
On CheckedItem that is not the signature of an event handler
Like #Blam said your immediate problem is resolveable by actually setting an event handler for the CheckBox "MyCheckBox."
<CheckBox x:Name="MyCheckBox" IsChecked="{Binding IsChecked,Mode=TwoWay}"
Checked="MyCheckBox_Checked"/>
private void MyCheckBox_Checked(object sender, RoutedEventArgs e)
{
MessageBox.Show("Checked");
}
2 other things:
If you keep the property public ShowingModel SelectedItem, then I would move the RaisePropertyChanged inside of the if statement. Better yet, make each of the variables you're setting their own property like:
double MyPrice
{
get {return price;}
set { if(price >= 0.0)/* Don't want a negative price. \m/*/
{ price = value; RaisePropertyChanged("MyPrice"); } }
}
If you have it this way for deleting an item, then I would suggest making that clearer for future reference.
I would highly suggest you take a look at few other resources:
Databinding a listbox to an ObservableCollection in code. <-- The question was correct, and has the best way to do this.
Databinding a listbox to an ObservableCollection in XAML.
WPF Tutorial | DataTemplates.
Making the list item check the checkbox.