How to handle events in a custom control Style / DataTemplate - c#

I have a custom control and a seperate ResourceDictionary.
As you can see, I have already implemented a version with a Command which is working! But I want to know, if it is possible that I can register this event directly to my code behind? I need to manipulate the clicked item.
Code (Trimmed)
public class HTBoard : Control, INotifyPropertyChanged
{
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
if (this.Template != null)
{
_ListBox = GetTemplateChild("ContentListbox") as ListBox;
_DragSelectionCanvas = GetTemplateChild("DragSelectionCanvas") as Canvas;
_DragSelectionBorder = GetTemplateChild("DragSelectionBorder") as Border;
//_Item = GetTemplateChild("Item") as ContentPresenter;
if (_ListBox == null || _DragSelectionCanvas == null || _DragSelectionBorder == null)
{
}
else
{
//_Item.MouseDown += Item_MouseDown;
//_Item.MouseUp += Item_MouseUp;
//_Item.MouseMove += Item_MouseMove;
this.MouseDown += HTBoard_MouseDown;
this.MouseUp += HTBoard_MouseUp;
this.MouseMove += HTBoard_MouseMove;
}
}
}
}
Style (Full)
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:HTFramework="clr-namespace:HTFramework">
<Style TargetType="{x:Type HTFramework:HTBoard}">
<Style.Resources>
<DataTemplate DataType="{x:Type HTFramework:HTBoardItem}">
<Grid
Background="#FFD62626"
UseLayoutRounding="True"
Margin="0,2,2,2">
<ContentPresenter
x:Name="Item"
Content="{Binding FrameworkElement}"
Width="{Binding FrameworkElement.Width}"
Height="{Binding FrameworkElement.Height}"
UseLayoutRounding="True">
<ContentPresenter.InputBindings>
<MouseBinding
Gesture="LeftClick"
Command="{Binding RelativeSource={RelativeSource AncestorType=HTFramework:HTBoard}, Path=ItemClickCommand}" ></MouseBinding>
</ContentPresenter.InputBindings>
<ContentPresenter.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="{Binding Rotation}"/>
<TranslateTransform/>
</TransformGroup>
</ContentPresenter.RenderTransform>
</ContentPresenter>
</Grid>
</DataTemplate>
</Style.Resources>
<Style.Setters>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type HTFramework:HTBoard}">
<Grid Background="Transparent">
<ListBox
x:Name="ContentListbox"
ItemsSource="{Binding ItemSource, RelativeSource={RelativeSource TemplatedParent}}"
SelectionMode="Extended"
Background="{TemplateBinding Background}"
Width="{Binding Path=Width, RelativeSource={RelativeSource TemplatedParent}}"
Height="{Binding Path=Height, RelativeSource={RelativeSource TemplatedParent}}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Canvas></Canvas>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Canvas.Left" Value="{Binding X}"></Setter>
<Setter Property="Canvas.Top" Value="{Binding Y}"></Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
<Canvas
x:Name="DragSelectionCanvas"
Visibility="Collapsed">
<Border
x:Name="DragSelectionBorder"
BorderBrush="Red"
BorderThickness="1"
Background="LightBlue"
CornerRadius="1"
Opacity="0.5"></Border>
</Canvas>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>

Yes, you can.
You just have to declare the class in the definition of the ResourceDictionary:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:HTFramework="clr-namespace:HTFramework"
x:Class="HTFramework.HTBoardResources">
Then you add a new code file which has the name of your existing ResourceDictionary followed by .cs. E.g. if your ResourceDictionary file name is HTBoardResources.xaml then the file name for the code behind needs to be HTBoardResources.xaml.cs.
The class in the code behind file should look like this:
namespace HTFramework
{
public partial class HTBoardResources : ResourceDictionary
{
}
}
You can now declare the EventHandler of any element in your Style in this new class.
(Technically you don't have to specify : ResourceDictionary but if you do then you see at one glance that you are in a ResourceDictionary.)

You can write your style in a different file, then attach a C# class to it with x:Class="HandlerClass".
You can handle all events there, but keep in mind it does not have access to anything but the current item.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:HTFramework="clr-namespace:HTFramework"
x:Class="HandlerClass">

Related

Set checkbox style template label programmaticaly WPF

I created a style for a checkbox in WPF and created an array of those checkboxes programmaticaly. The style is as follows
<Style x:Key="deviceZoom" TargetType="{x:Type CheckBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<DockPanel x:Name="dockPanel">
<Canvas Width="24.15" Height="23">
<Image Source="/Resources/Icons/deviceUnselectedDiscrete.png" x:Name="DeviceImage" Width="12" Height="19" Canvas.Top="4"/>
<Border x:Name="borderDevice"
CornerRadius="5"
Width="20"
Height="10"
Background="#222528"
BorderThickness="0"
Canvas.Top="1"
Canvas.Left="4.15">
<TextBlock x:Name="numBoards" HorizontalAlignment="Center" VerticalAlignment="Center" Padding=".1" FontSize="8" Foreground="White" Text="99"/>
</Border>
</Canvas>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And then I create some checkboxes like so and add to the root canvas
Style style = canvas.FindResource("deviceZoom") as Style;
var deviceCheckbox = new CheckBox();
canvas.Children.Add(deviceCheckbox);
deviceCheckbox.Style = style;
//Here I would like to set the label text
Now I would like to set from code behind a value to the label numBoards every time I have new data, but I don't know how. I tried using Dynamic Properties but didn't manage to set them well since the checkbox is created programmaticaly, and tried with binding but without success
CheckBox has Content property. Binding TextBlock.Text in template to owner Content via TemplateBinding.
<Style x:Key="deviceZoom" TargetType="{x:Type CheckBox}">
<Setter Property="Template" >
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<DockPanel x:Name="dockPanel">
<Canvas Width="24.15" Height="23">
<Image Source="/Resources/Icons/deviceUnselectedDiscrete.png" x:Name="DeviceImage" Width="12" Height="19" Canvas.Top="4"/>
<Border x:Name="borderDevice"
CornerRadius="5"
Width="20"
Height="10"
Background="#222528"
BorderThickness="0"
Canvas.Top="1"
Canvas.Left="4.15">
<TextBlock x:Name="numBoards"
HorizontalAlignment="Center" VerticalAlignment="Center"
Padding=".1" FontSize="8" Foreground="White"
Text="{TemplateBinding Content}"/>
</Border>
</Canvas>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then you can assign Content and it will be displayed in TextBlock:
deviceCheckbox.Content = "I am deviceCheckbox";
first, add UserControl. and add new property. it bind numBoards. XAML is ..
<UserControl x:Class="yourproject.myCheckBox"
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:local="clr-namespace:yourproject"
mc:Ignorable="d" x:Name="rootCtrl"
d:DesignHeight="450" d:DesignWidth="800">
<Canvas>
<CheckBox DataContext="{Binding ElementName=rootCtrl}" >
<CheckBox.Template>
<ControlTemplate TargetType="{x:Type CheckBox}">
<DockPanel x:Name="dockPanel">
<Canvas Width="24.15" Height="23">
<Image Source="/Resources/Icons/deviceUnselectedDiscrete.png" x:Name="DeviceImage" Width="12" Height="19" Canvas.Top="4"/>
<Border x:Name="borderDevice"
CornerRadius="5"
Width="20"
Height="10"
Background="#222528"
BorderThickness="0"
Canvas.Top="1"
Canvas.Left="4.15">
<TextBlock x:Name="numBoards" HorizontalAlignment="Center" VerticalAlignment="Center" Padding=".1" FontSize="8" Foreground="White" Text="{Binding NumBoards}"/>
</Border>
</Canvas>
</DockPanel>
</ControlTemplate>
</CheckBox.Template>
</CheckBox>
</Canvas>
</UserControl>
Code is ..
public partial class myCheckBox : UserControl, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
var handler = this.PropertyChanged;
if (handler != null)
{
handler(this, e);
}
}
private string _NumBoards = "77";
public string NumBoards
{
get
{
return _NumBoards;
}
set
{
_NumBoards = value;
OnPropertyChanged("NumBoards");
}
}
public myCheckBox()
{
InitializeComponent();
}
}
and use myCheckBox control
var deviceCheckbox = new myCheckBox();
deviceCheckbox.NumBoards = "20";
canvas.Children.Add(deviceCheckbox);

how to change button background color in c#

How can I change button background color programatically in Windows Phone Application.
Here is my xaml code.
<Style TargetType="Button" x:Key="TabButtonLast">
<Setter Property="Foreground" Value="Navy"/>
<Setter Property="Background" Value="Green" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border CornerRadius="15,15,15,15" Background="Green" >
<ContentPresenter x:Name="contentPresenter" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Button Name="btnNext" Style="{StaticResource TabButtonLast}" Content="Next" Height="23" HorizontalAlignment="Left" Margin="131,311,0,0" VerticalAlignment="Top" Width="75" Click="btnNext_click" />
I tried using "using System.Drawing" yourButtonName.BackColor = Color.Red;
but it doesn't seem to work.Any help will be greatly appreciated.
You need to modify your style as follows:
<Style TargetType="Button" x:Key="TabButtonLast">
<Setter Property="Foreground" Value="Navy"/>
<Setter Property="Background"
Value="{Binding Background, RelativeSource={RelativeSource Self}}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border CornerRadius="15,15,15,15" Background="{TemplateBinding Background}">
<ContentPresenter x:Name="contentPresenter" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
1) If you want static background:
<Button Background="Red" Name="btnNext" Style="{StaticResource TabButtonLast}" Content="Next" Height="23" HorizontalAlignment="Left" Margin="131,311,0,0" VerticalAlignment="Top" Width="75" Click="btnNext_click" />
2) To change Backcolor from code:
private void ChangeButtonColor()
{
btnNext.Background = "Red";
}
3) Using MVVM approach example:
"Frontend":
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication3"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style TargetType="Button" x:Key="TabButtonLast">
<Setter Property="Foreground" Value="Navy"/>
<Setter Property="Background"
Value="{Binding Background, RelativeSource={RelativeSource Self}}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border CornerRadius="15,15,15,15" Background="{TemplateBinding Background}">
<ContentPresenter x:Name="contentPresenter" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Button Style="{StaticResource TabButtonLast}" Content="CHANGE COLOR" Background="{Binding BtnBackColor}"
Margin="50" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Click="Button_Click" />
</Grid>
</Window>
"Backend":
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Media;
namespace WpfApplication3
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
public Brush BtnBackColor { get; set; } = new SolidColorBrush(Colors.Red);
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
private void Button_Click(object sender, RoutedEventArgs e)
{
Random r = new Random();
//Without Binding variant
//btnNext.Background = new SolidColorBrush(Color.FromRgb((byte)r.Next(1, 255),
// (byte)r.Next(1, 255), (byte)r.Next(1, 233)));
//MVVM approach variant
BtnBackColor = new SolidColorBrush(Color.FromRgb((byte)r.Next(1, 255),
(byte)r.Next(1, 255), (byte)r.Next(1, 233)));
OnPropertyChanged("BtnBackColor");
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Smth like this should work...
you can change the background color in code like this:
btnNext.Background = new SolidColorBrush(Windows.UI.Colors.Red);
You can try it with Data Binding. Data Binding is a nice and simpel. At the beginning you have to read a little but it is worth it.
Especially for MVVM applications.

how to select item on ExpanderDoubleClick Header in Listview

I have a ListView with different itemTemplate, and each itemTemplates have an ExpanderDoubleClick : Expander inside
I would like to select items in extended Mode in a listview with custom selection design (declared in each items UserControl).
So here is my xaml for the listView:
<ListView x:Name="ListViewModules" ItemsSource="{Binding ListOfModules}"
ItemContainerStyle="{StaticResource ContainerListViewItemStyle}"
ItemTemplateSelector="{DynamicResource ModuleTemplateSelector}"
SelectionMode="Extended"
dd:DragDrop.IsDragSource="True"
dd:DragDrop.IsDropTarget="True"
dd:DragDrop.UseDefaultDragAdorner="True"
Grid.Column="0" Grid.Row="0" Height="494" Width="634" Background="#FFCDCDCD"
ScrollViewer.HorizontalScrollBarVisibility="Hidden" ScrollViewer.VerticalScrollBarVisibility="Visible"
BorderBrush="#666666" BorderThickness="1" Padding="0"
ClipToBounds="True" SnapsToDevicePixels="True" >
</ListView>
with styles for removing the standard blue selection (declared in App.xaml):
<Style x:Key="ContainerListViewItemStyle" TargetType="{x:Type ListViewItem}">
<Setter Property="Margin" Value="2,2,2,0"/>
<Setter Property="dd:DragDrop.DragSourceIgnore" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Border x:Name="Bd" BorderBrush="Transparent" BorderThickness="0" Background="Transparent" Padding="0" SnapsToDevicePixels="true">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I have different ItemTemplates with each "UserControl's" and here an exemple of one of them with it's selection design :
<UserControl x:Class="Topinambour.Templates.Modules.DelayTemplate" ...>
<Grid Width="602" MinHeight="24">
<Grid.ColumnDefinitions> <ColumnDefinition Width="40"/><ColumnDefinition /> </Grid.ColumnDefinitions>
<ToggleButton x:Name="TgBtIsActive" IsChecked="{Binding IsChecked}" IsThreeState="{Binding IsThreeState}" Grid.Column="0" Height="24" Width="40" click="TgBtIsActive_Click"/>
<templates:ExpanderDoubleClick x:Name="ModuleExpander" IsExpanded="{Binding IsExpanded, Mode=OneWay}" Height="auto" Template="{DynamicResource TemplateExpander}" Grid.Column="1" Margin="4,0,0,0" Collapsed="Expander_Collapsed" Expanded="Expander_Expanded" HorizontalContentAlignment="Center" VerticalContentAlignment="Center">
<templates:ExpanderDoubleClick.Resources>
<Style x:Key="ExpanderHeaderStyle" TargetType="{x:Type ToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border x:Name="BorderIndent" BorderBrush="Gray" BorderThickness="1" Height="24" Width="558" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Padding="{Binding Indent}">
... my Header Content ...
</Border>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding IsExpanded}" Value="true">
<Setter Property="IsEnabled" TargetName="TbComment" Value="true"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListViewItem}}" Value="true">
<Setter Property="Background" TargetName="headerCanvas" Value="#999999"/>
<Setter Property="BorderBrush" TargetName="TbComment" Value="#666666"/>
<Setter Property="Foreground" TargetName="LbHeaderTitle" Value="White"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</templates:ExpanderDoubleClick.Resources>
<Border Background="White" BorderBrush="#666666" BorderThickness="1,0,1,1" Height="136" Width="558">
<Grid>
... my Expanded Content ...
</Grid>
</Border>
</templates:ExpanderDoubleClick>
</Grid>
and here the ExpanderDoubleClick.cs :
public class ExpanderDoubleClick: Expander
{
private static readonly DependencyPropertyKey IsMouseDoubleClickedPropertyKey = DependencyProperty.RegisterReadOnly(
"IsMouseDoubleClicked",typeof(Boolean),typeof(ExpanderDoubleClick),new FrameworkPropertyMetadata(false));
public static readonly DependencyProperty IsMouseDoubleClickedProperty = IsMouseDoubleClickedPropertyKey.DependencyProperty;
public Boolean IsMouseDoubleClicked
{
get { return (Boolean)GetValue(IsMouseDoubleClickedProperty); }
}
static ExpanderDoubleClick()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ExpanderDoubleClick), new FrameworkPropertyMetadata(typeof(ExpanderDoubleClick)));
}
protected override void OnMouseDoubleClick(MouseButtonEventArgs e)
{
base.OnMouseDoubleClick(e);
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
ContentControl contentControl = base.GetTemplateChild("HeaderSite") as ContentControl;
if (contentControl != null)
{
contentControl.AddHandler(ContentControl.MouseDoubleClickEvent, new MouseButtonEventHandler(ExpanderHeader_MouseDoubleClick), true);
}
}
private void ExpanderHeader_MouseDoubleClick(Object sender, MouseButtonEventArgs e)
{
base.SetValue(IsMouseDoubleClickedPropertyKey, !IsMouseDoubleClicked);
base.IsExpanded= !base.IsExpanded;
}
}
the selection is not working when I click on the header of the expander but if I open it and click inside the expandedContent, it select the item ! what did I miss ? thank you for the reply.
I finally found a pretty good solution that keep my extended mode selection.
since the header seams to not receive Click event to handle.
I looked up the tree debug, and it shows that the click on header does not go through the "ListViewItem"
so I add an OnMouseLeftButtonDown Event on my border x.Name="BorderIdent" and then add RaisedEvent back to it's itemTemplate
like so :
private void BorderIndent_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
ListViewItem lvItem = UITools.FindAncestor<ListViewItem>(e.OriginalSource as DependencyObject);
bool isListViewItem = lvItem != null;
if (isListViewItem)
{
lvItem.RaiseEvent(e);
}
}
UITools.FindAncestor : is here
and all worked perfectly :)

How to bind text to my custom XAML control?

I want to bind a DependencyProperty to my TextBox, what I need to do is to create a control that allows me to write a text in its property "Letter" and sets it as the text of the TextBlock defined in the template. I've never done this before so I'm not sure of how to do it.
Here's the .xaml:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:My_App">
<Style TargetType="local:GameLetter" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:GameLetter">
<Grid>
<Image Source="Assets/imgs/letter_key.png"/>
<Viewbox Margin="10,0">
<TextBlock x:Name="textBlock" FontFamily="Assets/fonts/avenirnext.ttf#Avenir Next" Text="{Binding Letter}" Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Viewbox>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And here's the .cs:
public sealed class GameLetter : Control
{
public GameLetter()
{
this.DefaultStyleKey = typeof(GameLetter);
}
public static readonly DependencyProperty LetterProperty =
DependencyProperty.Register("Letter", typeof(string), typeof(GameLetter), new PropertyMetadata(null));
public string Letter
{
get { return (string)GetValue(LetterProperty); }
set { SetValue(LetterProperty, value); }
}
}
You're close. The problem with your binding is that it'll search the Letter property on your datacontext, not on your control. You can fix that by using a TemplateBinding:
<Style TargetType="local:GameLetter" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:GameLetter">
<Grid>
<Image Source="Assets/imgs/letter_key.png"/>
<Viewbox Margin="10,0">
<TextBlock x:Name="textBlock" FontFamily="Assets/fonts/avenirnext.ttf#Avenir Next" Text="{TemplateBinding Letter}" Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Viewbox>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Binding RadioButton.IsChecked with Listbox.SelectedItem

My View is clickable like a radiobutton with about 7 other of these radiobuttons, but my listbox is not updating it's selected property unless I click outside of my radiobutton.
Basically I have a AbstractTask as my base. I have 7 child classes. I want to be able to select one of these AbstractTasks. That's all i'm after. So in my main window i have this.
<Window x:Class="AdvancedTaskAssigner.View.MainWindowView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:v="clr-namespace:AdvancedTaskAssigner.View"
Title="MainWindowView" Height="300" Width="300" SizeToContent="Height">
<DockPanel>
<TextBlock Text="TextBlock" DockPanel.Dock="Top" />
<TextBlock Text="{Binding ElementName=listTasks, Path=SelectedItem.Name}" DockPanel.Dock="Top" />
<ListBox x:Name="listTasks" ItemsSource="{Binding Tasks}" HorizontalContentAlignment="Stretch" SelectedItem="{Binding IsSelected}">
<ListBox.ItemTemplate>
<DataTemplate>
<v:AbstractTaskView />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
</Window>
since this is a library and not a application I had to put this in the Constructor of MainWindowView
MainWindowView.xaml.cs
public MainWindowView()
{
InitializeComponent();
var atvm = new ViewModel.MainWindowViewModel();
atvm.LoadTasks();
this.DataContext = atvm;
}
MainWindowViewModel.cs
class MainWindowViewModel
{
internal void LoadTasks()
{
var assembly = Assembly.GetAssembly(typeof(AbstractTask)).GetTypes().Where(t => t.IsSubclassOf(typeof(AbstractTask)));
Type[] typelist = GetTypesInNamespace(Assembly.GetAssembly(typeof(AbstractTask)), typeof(AbstractTask));
foreach (Type t in typelist)
{
if(!t.IsAbstract && t.BaseType.Equals(typeof(AbstractTask)))
{
tasks.Add(new AbstractTaskViewModel(t));
}
}
}
private Type[] GetTypesInNamespace(Assembly assembly, Type baseClass)
{
return assembly.GetTypes().Where(t => t.IsSubclassOf(baseClass)).ToArray();
}
private ObservableCollection<AbstractTaskViewModel> tasks = new ObservableCollection<AbstractTaskViewModel>();
public ObservableCollection<AbstractTaskViewModel> Tasks
{
get { return tasks; }
}
}
AbstractTaskViewModel.cs
public class AbstractTaskViewModel
{
public AbstractTaskViewModel(Type task)
{
if (!task.IsSubclassOf(typeof(AbstractTask)))
{
throw new NotSupportedException(string.Format("{0} is not a subclass of AbstractTask", task.Name));
}
Task = task;
}
public string Description
{
get
{
return GetCustomAttribute(0);
}
}
public string Name
{
get
{
return GetCustomAttribute(1);
}
}
public bool IsSelected{get;set;}
private string GetCustomAttribute(int index)
{
var descriptions = (DescriptionAttribute[])Task.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (descriptions.Length == 0)
{
return null;
}
return descriptions[index].Description;
}
protected readonly Type Task;
}
AbstractTaskView.xaml
<RadioButton
x:Class="AdvancedTaskAssigner.View.AbstractTaskView"
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" d:DesignHeight="300" d:DesignWidth="300" GroupName="AbstractTasks" Background="Transparent" IsChecked="{Binding IsSelected, Mode=TwoWay}">
<RadioButton.Template>
<ControlTemplate TargetType="{x:Type RadioButton}">
<Grid>
<Border x:Name="MyHead" BorderBrush="Black" BorderThickness="2" CornerRadius="5" Background="LightGray" Margin="20,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" Panel.ZIndex="2">
<TextBlock Text="{Binding Name}" Margin="5,2" MinWidth="50" />
</Border>
<Border x:Name="Myoooo" BorderBrush="Black" BorderThickness="2" CornerRadius="5" Background="Transparent" Margin="0,10,0,0" Panel.ZIndex="1">
<TextBlock Text="{Binding Description}" Margin="5,15,5,2" />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="MyHead" Property="Background" Value="LightGreen" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</RadioButton.Template>
</RadioButton>
this is what i am getting..
I want the green border to be the selected item. not what the Listbox's Selected item is. The bottom text box is the name of the selected item.
There are some issues related to binding IsChecked property of RadioButton. You can read about it here or here. You can apply the solution presented in the first link using your AbstractTaskView instead of RadioButton. Replace your listbox in MainWindowView with the code:
<ListBox x:Name="listTasks" ItemsSource="{Binding Tasks}" HorizontalContentAlignment="Stretch">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<v:AbstractTaskView Content="{TemplateBinding Content}"
IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsSelected}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
You have to also remove the folowing part of code from AbstractTaskView:
IsChecked="{Binding IsSelected, Mode=TwoWay}"
I hope you don't need IsSelected property of AbstractTaskViewModel to be set. But if you do, you can set it for example in Checked event handler in AbstractTaskView code behind (I know it's not pretty solution).
I see you're binding the IsSelected (boolean) to the SelectedItem (object)

Categories