WPF navigation and destroy current UserControl - c#

I'm trying to build a small navigation system in my WPF application. I'm using this tutorial to navigate between pages. I want to add 'Go back' functionality on top of it for one UserControl.
I have a UserControl Orders and another UserControl Order. Orders is shown in MainWindow and when I click on an button, Order UserControl should be shown in the same place in MainWindow. I tried to put a reference to the Orders usercontrol in the Order usercontrol and navigate to the Orders through Order. But the Order isn't destroyed since I'm using a variable from that class.
How can I make sure that when I navigate to Order form Orders, the Orders isn't destroyed and when I navigate to Orders from Order, Order is destroyed.
Button click event handler in Orders Class:
private void ShowOrder(object sender, RoutedEventArgs e)
{
Order order = new Order();
Switcher.Switch(order);
}
Return back button click handler in Order Class
public UserControl parent;
private void ReturnBack(object sender, RoutedEventArgs e)
{
Switcher.Switch(parent);
}

I usually do the next pattern whice uses ControlTemplate, lets say you have in your class:
private Enums.View _currView;
public Enums.View CurrView
{
get
{
return _currView;
}
set
{
_currView = value;
OnPropertyChanged("CurrView");
}
}
When Enums.View is:
public enum View
{
ViewA = 1,
ViewB = 2,
ViewC = 3,
}
Then, using Binding to CurrView above we change the view when it changes:
<UserControl ...
xmlns:Views="clr-namespace:CustomersManager.View"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<!--*********** Control templates ***********-->
<ControlTemplate x:Key="DefultTemplate">
<Views:DefultCustomersView/>
</ControlTemplate>
<ControlTemplate x:Key="A">
<Views:ViewAllCustomersView />
</ControlTemplate>
<ControlTemplate x:Key="B">
<Views:AddNewCustomersView />
</ControlTemplate>
<ControlTemplate x:Key="C">
<Views:EditCustomersView />
</ControlTemplate>
</UserControl.Resources>
<Border BorderBrush="Gray" BorderThickness="2">
<Grid>
<ContentControl DataContext="{Binding}" >
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="Template" Value="{StaticResource DefultTemplate}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=CurrView}" Value="ViewA">
<Setter Property="Template" Value="{StaticResource A}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=CurrView}" Value="ViewB">
<Setter Property="Template" Value="{StaticResource B}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=CurrView}" Value="ViewC">
<Setter Property="Template" Value="{StaticResource C}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl >
</Grid>
</Border>
</UserControl>

Related

Assign button Click event through TemplateBinding on Avalonia

I have a TemplatedControl SoftwareReleaseControl, which displays some texts and a button. I need this button to inherit its Click event from the property OnInstallClick that is specified when creating the SoftwareReleaseControl control.
The problem is: I can't make it work. It does not bind to the template's property. I've tried copying source code from Avalonia's button (ClickEvent) to the control's Code-Behind. It shows as an EventHandler, but is not passed to the button, and also gives an Unable to find suitable setter or adder [...] error.
SoftwareReleaseControl.xaml:
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="using:Updater.Controls">
<Design.PreviewWith>
<StackPanel Spacing="5">
<Panel Classes="Spacing"/>
<my:SoftwareReleaseControl Title="..." Version="..." Description="..." Installed="..."/>
<my:SoftwareReleaseControl Title="..." Version="..." Description="..." Installed="..."/>
</StackPanel>
</Design.PreviewWith>
<Style Selector="TextBlock">
<Setter Property="Foreground" Value="{DynamicResource text}"/>
<Setter Property="FontFamily" Value="Lato"/>
</Style>
[...]
<Style Selector="my|SoftwareReleaseControl">
[...]
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Panel Background="{TemplateBinding Background}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
Height="{TemplateBinding Height}"
MinWidth="{TemplateBinding MinWidth}" Width="{TemplateBinding Width}">
<Grid Margin="{TemplateBinding Padding}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
RowDefinitions="46, *, 40">
[...]
<StackPanel Grid.Row="2" Orientation="Horizontal">
======= HERE ===>> <Button x:Name="PART_footer_installButton"
Content="Instalar"
======= PROBLEM ===>> Click="{TemplateBinding OnInstallClick}">
<Button.Styles>
<Style Selector="Button#PART_footer_installButton">
<Setter Property="VerticalAlignment" Value="Bottom"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Foreground" Value="{DynamicResource text}"/>
<Setter Property="FontSize" Value="16"/>
<Setter Property="Tag" Value="{TemplateBinding Tag}"/>
</Style>
<Style Selector="Button#PART_footer_installButton:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource text}"/>
</Style>
</Button.Styles>
</Button>
</StackPanel>
</Grid>
</Panel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Styles>
SoftwareReleaseControl.xaml.cs (code-behind):
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
using System;
namespace Updater.Controls
{
public partial class SoftwareReleaseControl : TemplatedControl
{
public SoftwareReleaseControl()
{
}
public static readonly RoutedEvent<RoutedEventArgs> OnInstallClickEvent = RoutedEvent.Register<Button, RoutedEventArgs>(nameof(OnInstallClick), RoutingStrategies.Bubble);
public event EventHandler<RoutedEventArgs> OnInstallClick
{
add => AddHandler(OnInstallClickEvent, value);
remove => RemoveHandler(OnInstallClickEvent, value);
}
[...]
}
}
MainWindow.xaml (where I'm trying to show the controls):
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:Updater.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:my="using:Updater.Controls"
mc:Ignorable="d" Width="800" Height="520"
x:Class="Updater.Views.MainWindow"
Icon="/Assets/avalonia-logo.ico"
Title="Updater">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Background="{DynamicResource window.background}"
RowDefinitions="40, *" ColumnDefinitions="*">
[...]
<ScrollViewer Grid.Row="1">
<StackPanel Spacing="5" x:Name="stk_releases">
<Panel Classes="Spacing"/>
==== HERE ===>> <my:SoftwareReleaseControl Title="..." Version="..." Description="..." Installed="..." OnInstallClick="{Binding btn_OnClick}"/>
<my:SoftwareReleaseControl Title="..." Version="..." Description="..." Installed="..." OnInstallClick="{Binding btn_OnClick}"/>
</StackPanel>
</ScrollViewer>
</Grid>
</Window>
It doesn't really matter if I will need to implement btn_OnClick in the MainWindow's code-behind or in the ViewModel.
The current code is giving me the errors:
Unable to find suitable setter or adder for property OnInstallClick of type Updater:Updater.Controls.SoftwareReleaseControl for argument Avalonia.Markup:Avalonia.Data.Binding, available setter parameter lists are: System.EventHandler[[Avalonia.Interactivity.RoutedEventArgs, Avalonia.Interactivity]] on MainWindow.xaml, on the OnInstallClick="{Binding btn_OnClick}".
Unable to find suitable setter or adder for property Click of type Avalonia.Controls:Avalonia.Controls.Button for argument Avalonia.Base:Avalonia.Data.IBinding, available setter parameter lists are: System.EventHandler1<Avalonia.Interactivity.RoutedEventArgs> on *SoftwareReleaseControl.xaml*, on the Click="{TemplateBinding OnInstallClick}".
Yes, I did specify the StyleInclude on App.xaml.
Why Click and not Command: I need the sender object so I can get the Tag property of the button. There will be many of this control on the window and I need to sort out which one got clicked.
tl;dr: How can I specify an event handler on my templated control, in a way that the button inside it can inherit the handler as its Click (not Command). Where will I need to implement the handler? ViewModel or CodeBehind?
I gave up on using Click, and instead found a way to send the button itself to a Command.
SoftwareReleaseControl.xaml:
[...]
<Button x:Name="PART_footer_installButton"
Command="{Binding _OnInstallClick}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}}">
<Button.Styles>
<Style Selector="Button#PART_footer_installButton">
<Setter Property="VerticalAlignment" Value="Bottom"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Foreground" Value="{DynamicResource text}"/>
<Setter Property="FontSize" Value="16"/>
<Setter Property="Tag" Value="{TemplateBinding Tag}"/>
</Style>
<Style Selector="Button#PART_footer_installButton:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource text}"/>
</Style>
</Button.Styles>
</Button>
[...]
SoftwareReleaseControl.xaml.cs:
namespace Updater.Controls
{
public partial class SoftwareReleaseControl : TemplatedControl
{
public SoftwareReleaseControl()
{
DataContext = this;
}
public event EventHandler InstallClick;
private void _OnInstallClick(object? sender)
{
EventHandler handler = InstallClick;
handler?.Invoke(sender, EventArgs.Empty);
}
[...]
}
}
MainWindow.xaml.cs:
namespace Updater.Views
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel(this);
for (int i = 0; i < 6; i++)
{
var t = new SoftwareReleaseControl();
t.Description = (string)App.Current.Resources["lorem.50"];
t.Installed = i % 2 == 0;
t.Tag = i;
t.InstallClick += T_InstallClick;
stk_releases.Children.Add(t);
}
}
private void T_InstallClick(object? sender, EventArgs e)
{
Debug.WriteLine("123");
if (sender is Button btn)
{
Debug.WriteLine(btn.Tag);
}
}
}
}

Get Control (Button) from parent in usercontrol

I have a window with different items and different views for each type.
I would like to access the button in the window (parent) from my code behind from the content control.
OutputConfigView:
<ContentControl Margin="5">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedOutputRendererTyp}" Value="{x:Type outTypes:XmlBarcodeRenderer}">
<Setter Property="ContentTemplate" Value="{StaticResource OutputRendererView}"/>
</DataTrigger>
<DataTrigger Binding="{Binding SelectedOutputRendererTyp}" Value="{x:Type outTypes:CsvBarcodeRenderer}">
<Setter Property="ContentTemplate" Value="{StaticResource CsvOutputRendererView}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
.
.
<Button x:Name="CloseButton"
Grid.Column="1"
Click="WindowClose"
Content="Ok"
Margin="0 0 0 -5"
HorizontalAlignment="Center"
VerticalAlignment="Bottom">
</Button>
OutputRendererView.xaml.cs:
public partial class OutputRendererView : UserControl
{
public OutputRendererView()
{
InitializeComponent();
}
private void Border_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var parentWindow = (OutputRendererView)this.Parent;
var button = (Button)parentWindow.FindName("CloseButton");
}
In this case the parentWindow is null.
How can I access the button of the calling window from the code behind of my control ?
To access the button inside the user control, you must first find the usercontrol and then the button inside it.
var button = (Button)((UserControl)parentWindow.FindName("userControlName")).FindName("CloseButton");

How do I select a tab with right mouse click event in WPF

I created a context menu for a tabcontrol which changes the name of the tab. However, if the mouse over on an unselected tab and mouse right clicked on context menu pops up. If I click the the menu item it changes the selected tab's name. For instance, I right clicked on Favorite 4 tab and tried to change its name but it changed first tab's name (selected tab) as shown below.
I would like to select the tab with right mouse click as well as with left mouse click so it will not cause confusion or not intentional tab name change.
XAML
<TabControl x:Name="FavoritesTabs" HorizontalAlignment="Stretch" Height="23"
Initialized="FavoritesTabs_Initialized" Margin="8,0,7,0"
MouseRightButtonDown="FavoritesTabs_MouseRightButtonDown" MouseEnter="FavoritesTabs_MouseEnter" >
<TabControl.ContextMenu>
<ContextMenu Name="tabContextMenu">
<MenuItem Header="Change Tab Name" Click="MenuItem_Click" />
<MenuItem Header="Save Favorite Layers" />
</ContextMenu>
</TabControl.ContextMenu>
</TabControl>
C#
private void FavoritesTabs_Initialized(object sender, EventArgs e)
{
FavoritesList.Add("Favorite 1");
FavoritesList.Add("Favorite 2");
FavoritesList.Add("Favorite 3");
FavoritesList.Add("Favorite 4");
FavoritesTabs.ItemsSource = FavoritesList;
}
private void FavoritesTabs_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
}
private void MenuItem.Click(object sender, RoutedEventArgs e)
{
int index = FavoritesTabs.SelectedIndex;
FavoritesList[index] = "New tab";
}
I tried this answer but it did not work.
You have to style your TabControl adding event for MouseDown then select the tab item accordingly.
This is the code:
XAML
At fist, you need to define reosurces for TabControl style and also a style for a Grid. The latter is needed because you can't define an event handler within the TabControl style directly.
<Window x:Class="WpfApp7.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:WpfApp7"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<Style x:Key="GridStyle" TargetType="Grid">
<EventSetter Event="Mouse.MouseDown" Handler="UIElement_OnMouseDown"/>
</Style>
<Style x:Key="TabcontrolStyle" TargetType="{x:Type TabControl}">
<Style.Resources>
<Style TargetType="{x:Type TabItem}">
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid Height="20"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="true"
Style="{StaticResource GridStyle}">
<ContentPresenter Margin="10,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
ContentSource="Header" >
</ContentPresenter>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="false">
<Setter Property="Background" Value="Transparent" />
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="{x:Static SystemColors.ControlBrush}" />
</Trigger>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Background" Value="{x:Static SystemColors.ActiveCaptionBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Style.Resources>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid KeyboardNavigation.TabNavigation="Local">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TabPanel Name="HeaderPanel"
Panel.ZIndex="1"
IsItemsHost="True"
KeyboardNavigation.TabIndex="1" />
<ContentPresenter Name="PART_SelectedContentHost"
Margin="10"
Grid.Row="1"
ContentSource="SelectedContent" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<TabControl x:Name="MyTabControl" Style="{StaticResource TabcontrolStyle}">
<TabControl.ContextMenu>
<ContextMenu Name="tabContextMenu">
<MenuItem Header="Change Tab Name" />
<MenuItem Header="Save Favorite Layers" />
</ContextMenu>
</TabControl.ContextMenu>
<TabItem Header="First">First Content</TabItem>
<TabItem Header="Second">Second Content</TabItem>
<TabItem Header="Third">Third Content</TabItem>
</TabControl>
</Grid>
Code behind
In the code behind you can equals the TabItem header to selected the TabItem accordingly.
private void UIElement_OnMouseDown(object sender, MouseButtonEventArgs e)
{
ContentPresenter contentPresenter = null;
if (e.Source is Grid)
contentPresenter = (ContentPresenter) ((Grid) e.Source).Children[0];
else if (e.Source is ContentPresenter)
contentPresenter = ((ContentPresenter) e.Source);
if (contentPresenter == null) return;
var header = contentPresenter.Content.ToString();
var selectedIndex = -1;
foreach (var item in this.MyTabControl.Items)
{
selectedIndex++;
var tabItem = item as TabItem;
if (tabItem?.Header != null && tabItem.Header.ToString().Equals(header, StringComparison.InvariantCultureIgnoreCase))
{
this.MyTabControl.SelectedIndex = selectedIndex;
}
}
}

Wpf Style Trigger triggered only once

I have added a property trigger on a grid as below
<Grid.Style>
<Style TargetType="{x:Type Grid}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="ToolTip" Value=""></Setter>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="ToolTip" Value="{Binding StoredValue}"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Style>
The property is triggered only once when I hover over the grid.
What I require is that the property's (StoredValue) getter has to be called every time when MouseHover happens.
Please help
If you really want to update the tooltip every time it is displayed, you can utilize the ToolTipOpening event to refresh the binding:
<Grid x:Name="grid1" Background="Transparent">
<Grid.Style>
<Style TargetType="Grid">
<Setter Property="ToolTip" Value="{Binding StoredValue,TargetNullValue=''}"/>
<EventSetter Event="ToolTipOpening" Handler="grid1_ToolTipOpening"/>
</Style>
</Grid.Style>
</Grid>
Update the binding in code behind:
private void grid1_ToolTipOpening(object sender, ToolTipEventArgs e)
{
var s = sender as FrameworkElement;
var be = BindingOperations.GetBindingExpressionBase(s, FrameworkElement.ToolTipProperty);
if (be != null)
{
be.UpdateTarget();
}
}
Note: the TargetNullValue='' is necessary in case StoredValue would sometimes return a null. Otherwise the Tooltip wouldn't attempt to open and thus the ToolTipOpening would never happen and the value would never update from the null to a new value.
While I can't explain the nature of problem, here is a quick workaround: rise notification manually, then binding will refresh itself. You trade trigger for event:
<Grid Background="Transparent" MouseEnter="Grid_MouseEnter">
<Grid.Style>
<Style TargetType="{x:Type Grid}">
<!-- normal binding, this line is comment and should be gray -->
<Setter Property="ToolTip" Value="{Binding StoredValue}" />
</Style>
</Grid.Style>
</Grid>
public partial class MainWindow : Window, INotifyPropertyChanged
{
public string StoredValue => "123"; // is called every time mouse is entered
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
// rise notification manually
void Grid_MouseEnter(object sender, MouseEventArgs e) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(StoredValue)));
}

Setting up a Border Style template but allowing flexibility for values used

I have this Border style:
<Border.Style>
<Style x:Uid="Style_36" TargetType="Border">
<Setter x:Uid="Setter_94" Property="BorderBrush" Value="Transparent"/>
<Style.Triggers>
<DataTrigger x:Uid="DataTrigger_36" Binding="{Binding SelectedItem, ElementName=comboActiveStudentAssignmentType}"
Value="{x:Static StudentInfoEnums:StudentAssignmentType.Student1Main}">
<Setter x:Uid="Setter_95" Property="BorderBrush" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
I know how to place a style into the Window.Resources and then apply it to any control. But I need to tweak each instance. In the text:
<Border.Style>
<Style x:Uid="Style_36" TargetType="Border">
<Setter x:Uid="Setter_94" Property="BorderBrush" Value="Transparent"/>
<Style.Triggers>
<DataTrigger x:Uid="DataTrigger_36" Binding="{Binding SelectedItem, ElementName=comboActiveStudentAssignmentType}"
Value="{x:Static StudentInfoEnums:StudentAssignmentType.Student1Main}">
<Setter x:Uid="Setter_95" Property="BorderBrush" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
This bit:
Value="{x:Static StudentInfoEnums:StudentAssignmentType.Student1Main}">
needs to change for each Border on the window. So, how can I set up a style to simplify my code but allow this property to change?
Possible?
Update
Since each border should only diaplay when the combo is a certain value, and the suggestion was to put all the data triggers into the style template, I began by trying:
<Style x:Uid="Style_38" x:Key="StudentAssignmentFocusedBorder" TargetType="Border">
<Setter x:Uid="Setter_94" Property="BorderBrush" Value="Transparent"/>
<Style.Triggers>
<MultiDataTrigger x:Uid="MultiDataTrigger_5">
<MultiDataTrigger.Conditions>
<Condition x:Uid="Condition_11" Binding="{Binding SelectedtItem, ElementName=comboActiveStudentAssignmentType}" Value="{x:Static StudentInfoEnums:StudentAssignmentType.Student1Main}"/>
<Condition x:Uid="Condition_12" Binding="{Binding Name, Mode=OneWay, RelativeSource={RelativeSource Self}}" Value="borderMainHallStudent1"/>
</MultiDataTrigger.Conditions>
<Setter x:Uid="Setter_95" Property="BorderBrush" Value="Red"/>
</MultiDataTrigger>
</Style.Triggers>
</Style>
But that doesn't work.
This NOT beautiful but enhancing your possibilities, since you can bind your StudentInfoEnums:StudentAssignmentType.Student1Main-Enum.
Some random demo-XAML to Test:
<Window x:Class="SelectButtonSample.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:SelectButtonSample"
mc:Ignorable="d"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
Title="MainWindow" >
<Grid Height="200">
<StackPanel>
<Button Content="Click me" Width="80" Height="20" >
<i:Interaction.Behaviors>
<local:MyBorderBehavior MyEnumPropery="Two"/>
</i:Interaction.Behaviors>
</Button>
<CheckBox Content="Click me" x:Name="chk">
<i:Interaction.Behaviors>
<local:MyBorderBehavior MyEnumPropery="Three"/>
</i:Interaction.Behaviors>
</CheckBox>
<ListView>
<i:Interaction.Behaviors>
<local:MyBorderBehavior MyEnumPropery="One"></local:MyBorderBehavior>
</i:Interaction.Behaviors>
<ListViewItem Content="Item1">
<i:Interaction.Behaviors>
<local:MyBorderBehavior MyEnumPropery="Four"></local:MyBorderBehavior>
</i:Interaction.Behaviors>
</ListViewItem>
<ListViewItem>Item 2</ListViewItem>
<ListViewItem>Item 3</ListViewItem>
<ListViewItem>Item 4</ListViewItem>
</ListView>
</StackPanel>
</Grid>
</Window>
My Demo-Enum:
public enum MyEnum
{
One,
Two,
Three,
Four
}
The Magic:
public class MyBorderBehavior : Behavior<Control>
{
public MyEnum MyEnumPropery {
get { return (MyEnum) GetValue(MyEnumProperyProperty); }
set { SetValue(MyEnumProperyProperty, value); }
}
public static readonly DependencyProperty MyEnumProperyProperty = DependencyProperty.Register("MyEnumPropery", typeof(MyEnum), typeof(MyBorderBehavior), new PropertyMetadata(PropertyChangedCallback));
private static void PropertyChangedCallback(DependencyObject dO, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
var self = dO as MyBorderBehavior;
if (self != null && self._controlToColorBorder != null)
self.SetColor();
}
private Control _controlToColorBorder;
private void SetColor()
{
switch (this.MyEnumPropery)
{
case MyEnum.One:
this._controlToColorBorder.BorderBrush = Brushes.Yellow;
break;
case MyEnum.Two:
this._controlToColorBorder.BorderBrush = Brushes.Red;
break;
case MyEnum.Three:
this._controlToColorBorder.BorderBrush = Brushes.Green;
break;
case MyEnum.Four:
this._controlToColorBorder.BorderBrush = Brushes.DeepPink;
break;
}
}
protected override void OnAttached()
{
this._controlToColorBorder = this.AssociatedObject;
this._controlToColorBorder.Loaded += ControlToColorBorderLoaded;
base.OnAttached();
}
private void ControlToColorBorderLoaded(object sender, RoutedEventArgs e)
{
this.SetColor();
}
}
Notes:
As you can see, you have to use the
System.Windows.Interactivity-Assembly
This little Behavior can applied to everything of type Control
(Since Control has BorderBrush-Property)
I've implemented a DependencyProperty to make things bindable.
Four your purpose, you sure have to replace MyEnum with yours and
adjust the colors. Furthermore, you might have to implement another
DependencyProperty to bring your 2nd condition to the Behavior.
Hope this gives you a clue, on how you can get ahead with your code.

Categories