hi in my form(adminentitylist.xaml) file contains the code is below
<ResourceDictionary xmlns:local="clr-namespace:iWatch.Administration"
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"
xmlns:my="clr-namespace:iWatch.UILibrary;assembly=UILibrary"
xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid"
xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
xmlns:dxb="http://schemas.devexpress.com/winfx/2008/xaml/bars"
xmlns:cmd="clr-namespace:iWatch.UILibrary;assembly=UILibrary"
x:Class="AdminEntityList">
<ControlTemplate x:Key="AddImgBtnTemplate" TargetType="Button">
<Grid>
<Image Name="Normal" Source="/UILibrary;component/Themes/Default/Images/Add.png" Opacity="1.0" Height="18" Width="18"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Normal" Property="Opacity" Value="0.5"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Normal" Property="Opacity" Value="0.2"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="DelImgBtnTemplate" TargetType="Button">
<Grid>
<Image Name="Normal" Source="/UILibrary;component/Themes/Default/Images/Delete.png" Opacity="1.0" Height="18" Width="18"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Normal" Property="Opacity" Value="0.5"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Normal" Property="Opacity" Value="0.2"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style TargetType="{x:Type local:AdminEntityList}">
<Setter Property="FontFamily" Value="Calibri"/>
<Setter Property="dx:ThemeManager.ThemeName" Value="Office2007Black"/>
<Setter Property="Template" >
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:AdminEntityList}">
<DockPanel>
<DockPanel DockPanel.Dock="Top">
<StackPanel Name="StpFilter" Orientation="Horizontal" HorizontalAlignment="Left" Margin="5">
<ContentControl x:Name="FilterCriteriaArea" ContentTemplate="{TemplateBinding FilterCriteriaArea}"/>
</StackPanel>
<StackPanel Name="StpCountry" Orientation="Horizontal" HorizontalAlignment="Right" Margin="5" >
<Label Content="Select Country" Name="lblCountry" Style="{StaticResource lblNormal}" Margin="10,0,5,7" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Visibility="Collapsed"/>
<ComboBox Name="cbCountry" Width="170" Style="{StaticResource ddlNormal}" SelectedValue="{Binding CountryKey,Mode=TwoWay}" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5,2,10,0" Visibility="Collapsed"/>
<Button Content="Filter" Name="btnFilter" Width="70" Height="23" Margin="0,0,10,0" Visibility="Collapsed"/>
</StackPanel>
<StackPanel Name="actinact" Orientation="Horizontal" HorizontalAlignment="Left" Margin="5">
<CheckBox Name="chkactive" Height="18" Content="Active" Checked="chkactive_Checked"></CheckBox>
<CheckBox Name="chkinactive" Height="18" Content="In-Active"/>
</StackPanel>
<StackPanel Name="StpAddDel" Orientation="Horizontal" HorizontalAlignment="Right" Margin="5">
<Button Name="BtnAdd" Height="20" Width="20" Margin="5,0" Template="{StaticResource AddImgBtnTemplate}" />
<Button Name="BtnDel" Height="20" Width="20" Margin="5,0" Template="{StaticResource DelImgBtnTemplate}" />
</StackPanel>
</DockPanel>
<DockPanel Name="AMLDP">
<dxg:GridControl Name="genericGrid" AutoPopulateColumns="true" ShowBorder="False"
DesignTimeDataSourceRowCount="50" DataSource="{Binding}"
Padding="0" Margin="0,0,0,0" IsManipulationEnabled="True" dx:ThemeManager.ThemeName="CPCEGridTheme">
<dxg:GridControl.Resources>
<ResourceDictionary x:Key="CPCEGridTheme" Source="/UILibrary;component/Themes/Default/Styles/DataGrid/CPCEGridTheme.xaml" />
</dxg:GridControl.Resources>
<dxg:GridControl.View>
<dxg:TableView x:Name="tblGeneric" MultiSelectMode="Row" AllowGrouping="True" ClipToBounds="True" AutoWidth="True"
ShowGroupPanel="False" ShowHorizontalLines="True" ShowVerticalLines="False" AllowMoveColumnToDropArea="False" AllowDrop="False"
IsGroupPanelMenuEnabled="False" AllowEditing="False" NavigationStyle="Cell" Margin="0"
GroupRowStyle="{StaticResource OddEvenRowStyle}" VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Standard" AllowHorizontalScrollingVirtualization="True"
RowStyle="{StaticResource OddEvenRowStyle}" CellStyle="{StaticResource FocusedCellStyle}">
<dxg:TableView.RowCellMenuCustomizations>
<dxb:BarButtonItem Name="ctmView" IsVisible="False" Content="View" Command="{x:Static cmd:CustomCommands.View}" />
<dxb:BarButtonItem Name="ctmEdit" IsVisible="True" Content="Edit" Command="{x:Static cmd:CustomCommands.Edit}" />
<dxb:BarButtonItem Name="ctmMIQ" IsVisible="False" Content="Manage Interview Questions" Command="{x:Static cmd:CustomCommands.ManageInterviewQuestions}" />
<dxb:BarButtonItem Name="ctmActivate" IsVisible="False" Content="Activate" Command="{x:Static cmd:CustomCommands.Activate}" />
<dxb:BarButtonItem Name="ctmCopyInterviewType" IsVisible="False" Content="Copy Interview Type" Command="{x:Static cmd:CustomCommands.CopyInterviewType}" />
<dxb:BarButtonItem Name="ctmAssignInvGroup" IsVisible="False" Content="Assign Investigative Group" Command="{x:Static cmd:CustomCommands.AssignInvestigativeGroup}" />
<dxb:BarButtonItem Name="ctmCopySelected" IsVisible="False" Content="Copy From Selected" Command="{x:Static cmd:CustomCommands.CopyInterviewTemplate}" />
</dxg:TableView.RowCellMenuCustomizations>
</dxg:TableView>
</dxg:GridControl.View>
<dxg:GridControl.CommandBindings>
<CommandBinding x:Name="cmdEdit" Command="{x:Static cmd:CustomCommands.Edit}" />
<CommandBinding x:Name="cmdView" Command="{x:Static cmd:CustomCommands.View}" />
<CommandBinding x:Name="cmdMIQ" Command="{x:Static cmd:CustomCommands.ManageInterviewQuestions}" />
<CommandBinding x:Name="cmdActivate" Command="{x:Static cmd:CustomCommands.Activate}" />
<CommandBinding x:Name="cmdCopyInterviewType" Command="{x:Static cmd:CustomCommands.CopyInterviewType}" />
<CommandBinding x:Name="cmdAssignInvestigativeGroup" Command="{x:Static cmd:CustomCommands.AssignInvestigativeGroup}" />
<CommandBinding x:Name="cmdCopySelected" Command="{x:Static cmd:CustomCommands.CopyInterviewTemplate}" />
</dxg:GridControl.CommandBindings>
</dxg:GridControl>
</DockPanel>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
in the above code i created the checkbox checked event Checked="chkactive_Checked"
private void chkactive_Checked(object sender, RoutedEventArgs e)
{
}
but the event is not firing and i am getting an error is
Error 14 'AdminEntityList' does not contain a definition for
'chkactive_Checked' and no extension method 'chkactive_Checked'
accepting a first argument of type 'AdminEntityList' could be found
(are you missing a using directive or an assembly reference?)
please help me with is problem...
Here is a simple example:
<Window x:Class="CheckboxCheckedCommand.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<CheckBox Content="Case Sensitive" Command="{Binding checkedCommand}"/>
</Grid>
Codebehind:
public partial class MainWindow : Window
{
public ViewModel vm { get; set; }
public MainWindow()
{
InitializeComponent();
vm = new ViewModel();
this.DataContext = vm;
}
}
ViewModel:
public class ViewModel
{
public ICommand checkedCommand { get; set; }
public ViewModel()
{
checkedCommand = new CheckedCommand(this);
}
public void CheckedHandler()
{
//todo - implement your handler
}
}
And of course the Checked Unchecked command:
public class CheckedCommand : ICommand
{
private ViewModel _vm = null;
public CheckedCommand(ViewModel _viewModel)
{
_vm = _viewModel;
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_vm.CheckedHandler();
}
}
Let me know if you need more details, maybe a parameter which has to be sent from the view and received by the handler..
I see this as an easy and normal flow for MVVM. You have some instance/static method issue right there.. try the above approach, in my opinion is cleared and helps you decouple the things.
Oh, i forgot to say, Command="{Binding checkedCommand}" , is both applicable for Checked and Unchecked events.
Update 1
This can be your codebehind:
public partial class MainWindow : Window
{
public bool IsChecked
{
get { return (bool)GetValue(IsCheckedProperty); }
set { SetValue(IsCheckedProperty, value); }
}
// Using a DependencyProperty as the backing store for IsChecked. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsCheckedProperty =
DependencyProperty.Register("IsChecked", typeof(bool), typeof(MainWindow), new PropertyMetadata(false, new PropertyChangedCallback(PropertyChanged)));
private static void PropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
//textbox.ScrollToEnd(); //An object reference is required for the non-static field.
MainWindow localWindow = (MainWindow)obj;
Console.WriteLine(localWindow.TestString);
}
public string TestString { get; set; }
public MainWindow()
{
InitializeComponent();
TestString = "test";
this.DataContext = this;
}
}
And you CheckBox definition is this now:
<CheckBox Content="Case Sensitive" IsChecked="{Binding IsChecked}"/>
You basically define that DependencyProperty with the name IsChecked. Each time you check or uncheck it, the callback method defined there will be called. And may see an example on how to access an instance field from that static method. Good luck!
Related
I have a UWP application, and it has a page containing a few textbox controls bound to A.B.C[2].D, A.B.C[2].E, A.B.C[2].F, and so on
Now I want to move the text boxes to a separate UserControl to simplify my page's XAML but
still want them to be bound to A.B.C[2].D, A.B.C[2].E etc.
How can I achieve this?
Thank you
Here is my UserControl
<UserControl
x:Class="Inspecto.HWStatusDisplayControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Truphase360"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="250">
<Grid>
<Grid.Resources>
<Style x:Key="styleTxtBox" TargetType="TextBox">
<Setter Property="IsReadOnly" Value="True" />
<Setter Property="Width" Value="75"/>
</Style>
<Style x:Key="styleTxtBlk" TargetType="TextBlock">
<Setter Property="FontSize" Value="12" />
<Setter Property="Margin" Value="10"/>
<Setter Property="Width" Value="75" />
</Style>
</Grid.Resources>
<StackPanel Orientation="Vertical" Margin="20">
<TextBlock Text="{x:Bind Header}" FontSize="16" FontWeight="Bold" Margin="10">
</TextBlock>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Temp1" Style="{StaticResource styleTxtBlk}" />
<TextBox Style="{StaticResource styleTxtBox}" Text="{Binding Mode=OneWay, Path=Temperature1 }" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Temp2" Style="{StaticResource styleTxtBlk}" />
<TextBox Style="{StaticResource styleTxtBox}" Text="{Binding Mode=OneWay, Path=Temperature2 }" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="SW Version" Style="{StaticResource styleTxtBlk}" />
<TextBox Style="{StaticResource styleTxtBox}" Text="{Binding Mode=OneWay, Path=SWVersionStr }" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="HW Version" Style="{StaticResource styleTxtBlk}" />
<TextBox Style="{StaticResource styleTxtBox}" Text="{Binding Mode=OneWay, Path=HWVersionStr }" />
</StackPanel>
</StackPanel>
</Grid>
</UserControl>
The code block directly under exists inside a page and is repeated multiple times.
The TextBoxs' were bound to {x:Bind ViewModel.DeviceData.Status.Devices[0].Temperature1 } and so on inside the Page
Now I want to display the same from UserControl.
In the data object, the instance of Devices[] is replaced every few seconds. The new array was created by deserializing from JSON object and directly assigned to like
ViewModel.DeviceData.Status.Devices = FromJSON(string);
Thank you
I agree with #EldHasp. The solution for your scenario is that you might need to create a custom dependency property in the UserControl. Then pass the A.B.C object to this property of the UserControl via binding.
I've made a simple demo about this, you could take look at the code and adjust it for your scenario.
UserControl XAML
<Grid x:Name="MyGrid">
<Grid.Resources>
<Style x:Key="styleTxtBox" TargetType="TextBox">
<Setter Property="IsReadOnly" Value="True" />
<Setter Property="Width" Value="75"/>
</Style>
<Style x:Key="styleTxtBlk" TargetType="TextBlock">
<Setter Property="FontSize" Value="12" />
<Setter Property="Margin" Value="10"/>
<Setter Property="Width" Value="75" />
</Style>
</Grid.Resources>
<StackPanel Orientation="Vertical" Margin="20">
<TextBlock Text="{x:Bind Header}" FontSize="16" FontWeight="Bold" Margin="10">
</TextBlock>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Temp1" Style="{StaticResource styleTxtBlk}" />
<TextBox Style="{StaticResource styleTxtBox}" Text="{Binding MyDependencyProperty._List[0].Name}" />
</StackPanel>
</StackPanel>
</Grid>
UserControl Code
public AClass MyDependencyProperty
{
get { return (AClass)GetValue(MyDependencyPropertyProperty); }
set { SetValue(MyDependencyPropertyProperty, value); }
}
// Using a DependencyProperty as the backing store for MyDependencyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyDependencyPropertyProperty =
DependencyProperty.Register("MyDependencyProperty", typeof(AClass), typeof(TestUserControl), new PropertyMetadata(null));
public string Header = "TestHeader";
public TestUserControl()
{
this.InitializeComponent();
this.DataContext = this;
}
MainPage Xaml
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Foreground="Red" Text="{x:Bind ViewModel._AClass._List[1].Name}"/>
<local:TestUserControl Grid.Row="1" MyDependencyProperty="{x:Bind ViewModel._AClass}"/>
</Grid>
MainPage Code
public sealed partial class MainPage : Page
{
public TestViewModel ViewModel { get; set; }
public MainPage()
{
this.InitializeComponent();
ViewModel= new TestViewModel();
}
}
public class TestViewModel
{
public AClass _AClass { get; set; }
public TestViewModel()
{
_AClass = new AClass();
}
}
public class AClass
{
public List<BClass> _List { get; set; }
public AClass()
{
_List = new List<BClass>();
_List.Add(new BClass { Name = "123" });
_List.Add(new BClass { Name = "234" });
}
}
public class BClass
{
public string Name { get; set; }
}
And the result:
My question is based on one of the answer to this post:
Where is the WPF Numeric UpDown control?
answered by Mr. Squirrel.Downy.
What i would like to accomplish is a numeric updown control that increases/decreases with a larger amount when the buttons are pressed for a longer time, otherwise the increase/decrease is the normal amount. Also when the max/min is reached the buttons should disable.
I have a style based on a Slider which contains 2 buttons of type HoldButton (up/down, derived from RepeatButton) and a readonly TextBlock for the Value.
In the HoldButton i have 2 dependency properties for an ICommand. These are ClickAndHoldCommand and ClickCommand which are executed from either the OnPreviewMouseLeftButtonDown() or OnPreviewMouseLeftButtonUp() depending on the length of the mouse button press. In the xaml these are bound to Slider.IncreaseLarge and Slider.IncreaseSmall respectively.
How can i disable the up button when the max is reached and disable the down button when the min is reached? The difficulty is that when i for example disable the slider, the up mouse event does not work anymore...
<Style TargetType="{x:Type Slider}" x:Key="NumericUpDown">
<Style.Resources>
<Style x:Key="RepeatButtonStyle" TargetType="{x:Type RepeatButton}">
<Setter Property="Focusable" Value="false" />
<Setter Property="IsTabStop" Value="false" />
<Setter Property="Padding" Value="0" />
<Setter Property="Width" Value="20" />
</Style>
</Style.Resources>
<Setter Property="Stylus.IsPressAndHoldEnabled" Value="false" />
<Setter Property="SmallChange" Value="1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Slider}">
<Grid>
<Rectangle RadiusX="10" RadiusY="10" Stroke="{StaticResource SolidBrushLightGrey}" Fill="Black" StrokeThickness="1" />
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" x:Name="ControlName" Style="{StaticResource LabelStyle}" Margin="0,5,0,0" />
<TextBlock Grid.Row="1" x:Name="ControlUnits" Style="{StaticResource LabelStyle}" Margin="0,5,0,0" />
<usercontrols:HoldButton Grid.Row="2" Delay="250" Interval="375"
EnableClickHold="True"
ClickAndHoldCommand="{x:Static Slider.IncreaseLarge}"
ClickCommand="{x:Static Slider.IncreaseSmall}"
MaxWidth="60" Height="60" Width="60" Style="{StaticResource ButtonStyleGeneral}" Content="+">
</usercontrols:HoldButton>
<TextBlock Grid.Row="3" x:Name="Temperature" Style="{StaticResource LabelStyle}" Margin="0,5,0,0" FontSize="30" Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Value, StringFormat=N1}" />
<usercontrols:HoldButton Grid.Row="4" Delay="250" Interval="375"
EnableClickHold="True"
ClickAndHoldCommand="{x:Static Slider.DecreaseLarge}"
ClickCommand="{x:Static Slider.DecreaseSmall}"
MaxWidth="60" Height="60" Width="60" Style="{StaticResource ButtonStyleGeneral}" Content="-">
</usercontrols:HoldButton>
<Border x:Name="TrackBackground" Visibility="Collapsed">
<Rectangle x:Name="PART_SelectionRange" Visibility="Collapsed" />
</Border>
<Thumb x:Name="Thumb" Visibility="Collapsed" />
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
public partial class HoldButton : RepeatButton
{
private bool buttonIsHeldPressed;
public HoldButton()
{
InitializeComponent();
buttonIsHeldPressed = false;
this.PreviewMouseLeftButtonUp += OnPreviewMouseLeftButtonUp;
// RepeatButton fires click event repeatedly while button is being pressed!
this.Click += HoldButton_Click;
}
private void HoldButton_Click(object sender, RoutedEventArgs e)
{
Trace.WriteLine("HoldButton_Click()");
if (EnableClickHold)
{
if (numberButtonRepeats > 2)
{
ClickAndHoldCommand.Execute(this.CommandParameter);
e.Handled = true;
buttonIsHeldPressed = true;
}
numberButtonRepeats++;
}
}
public bool EnableClickHold
{
get { return (bool)GetValue(EnableClickHoldProperty); }
set { SetValue(EnableClickHoldProperty, value); }
}
public ICommand ClickAndHoldCommand
{
get { return (ICommand)GetValue(ClickAndHoldCommandProperty); }
set { SetValue(ClickAndHoldCommandProperty, value); }
}
public ICommand ClickCommand
{
get { return (ICommand)GetValue(ClickCommandProperty); }
set { SetValue(ClickCommandProperty, value); }
}
// Using a DependencyProperty as the backing store for ClickAndHoldCommand. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ClickAndHoldCommandProperty =
DependencyProperty.Register("ClickAndHoldCommand", typeof(ICommand), typeof(HoldButton), new UIPropertyMetadata(null));
// Using a DependencyProperty as the backing store for ClickCommand. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ClickCommandProperty =
DependencyProperty.Register("ClickCommand", typeof(ICommand), typeof(HoldButton), new UIPropertyMetadata(null));
// Using a DependencyProperty as the backing store for EnableClickHold. This enables animation, styling, binding, etc...
public static readonly DependencyProperty EnableClickHoldProperty =
DependencyProperty.Register("EnableClickHold", typeof(bool), typeof(HoldButton), new PropertyMetadata(false));
// Using a DependencyProperty as the backing store for MillisecondsToWait. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MillisecondsToWaitProperty =
DependencyProperty.Register("MillisecondsToWait", typeof(int), typeof(HoldButton), new PropertyMetadata(0));
public int MillisecondsToWait
{
get { return (int)GetValue(MillisecondsToWaitProperty); }
set { SetValue(MillisecondsToWaitProperty, value); }
}
private int numberButtonRepeats;
private void OnPreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (EnableClickHold)
{
numberButtonRepeats = 0;
if(!buttonIsHeldPressed)
{
ClickCommand?.Execute(this.CommandParameter);
}
buttonIsHeldPressed = false;
}
}
private void OnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Trace.WriteLine("OnPreviewMouseLeftButtonDown()");
if (EnableClickHold)
{
// When numberButtonRepeats comes above 1 then the button is considered to be pressed long
if (numberButtonRepeats > 1)
{
ClickAndHoldCommand?.Execute(this.CommandParameter);
}
numberButtonRepeats++;
}
}
}
<UserControl x:Class="Views.TemperatureControlView"
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:Views"
xmlns:cal="http://www.caliburnproject.org"
xmlns:controls="clr-namespace:UserControls"
mc:Ignorable="d"
d:DesignHeight="250" d:DesignWidth="150">
<Slider Minimum="{Binding MinimumTemperature}"
Maximum="{Binding MaximumTemperature}"
SmallChange="{Binding TemperatureTinySteps}"
LargeChange="{Binding TemperatureSmallSteps}"
Value="{Binding ControlValue}"
Style="{StaticResource NumericUpDown}" />
</UserControl>
You should extend the Slider control and implement the logic there.
Finally name the RepeatButton elements and move the Style to the Generic.xaml file.
public class CustomSlider : Slider
{
static CustomSlider()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomSlider), new FrameworkPropertyMetadata(typeof(CustomSlider)));
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this.PART_IncreaseButton = GetTemplateChild(nameof(this.PART_IncreaseButton)) as UIElement;
this.PART_DecreaseButton = GetTemplateChild(nameof(this.PART_DecreaseButton)) as UIElement;
}
protected override void OnValueChanged(double oldValue, double newValue)
{
base.OnValueChanged(oldValue, newValue);
if (this.PART_IncreaseButton == null
|| this.PART_DecreaseButton == null)
{
return;
}
this.PART_IncreaseButton.IsEnabled = newValue < this.Maximum;
this.PART_DecreaseButton.IsEnabled = newValue > this.Minimum;
}
private UIElement PART_IncreaseButton { get; set; }
private UIElement PART_DecreaseButton { get; set; }
}
Generic.xaml
Name the HoldButton elements "PART_IncreaseButton" and "PART_IncreaseButton" so that you can find them easily in the template.
<Style TargetType="{x:Type CustomSlider}">
<Style.Resources>
<Style x:Key="RepeatButtonStyle" TargetType="{x:Type RepeatButton}">
<Setter Property="Focusable" Value="false" />
<Setter Property="IsTabStop" Value="false" />
<Setter Property="Padding" Value="0" />
<Setter Property="Width" Value="20" />
</Style>
</Style.Resources>
<Setter Property="Stylus.IsPressAndHoldEnabled" Value="false" />
<Setter Property="SmallChange" Value="1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Slider}">
<Grid>
<Rectangle RadiusX="10" RadiusY="10" Stroke="{StaticResource SolidBrushLightGrey}" Fill="Black" StrokeThickness="1" />
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" x:Name="ControlName" Style="{StaticResource LabelStyle}" Margin="0,5,0,0" />
<TextBlock Grid.Row="1" x:Name="ControlUnits" Style="{StaticResource LabelStyle}" Margin="0,5,0,0" />
<usercontrols:HoldButton x:Name="PART_IncreaseButton"
Grid.Row="2"
Delay="250"
Interval="375"
EnableClickHold="True"
ClickAndHoldCommand="{x:Static Slider.IncreaseLarge}"
ClickCommand="{x:Static Slider.IncreaseSmall}"
MaxWidth="60"
Height="60" Width="60"
Style="{StaticResource ButtonStyleGeneral}"
Content="+" />
<TextBlock Grid.Row="3" x:Name="Temperature" Style="{StaticResource LabelStyle}" Margin="0,5,0,0" FontSize="30" Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Value, StringFormat=N1}" />
<usercontrols:HoldButton x:Name="PART_DecreaseButton"
Grid.Row="4"
Delay="250"
Interval="375"
EnableClickHold="True"
ClickAndHoldCommand="{x:Static Slider.DecreaseLarge}"
ClickCommand="{x:Static Slider.DecreaseSmall}"
MaxWidth="60"
Height="60" Width="60"
Style="{StaticResource ButtonStyleGeneral}"
Content="-" />
<Border x:Name="TrackBackground" Visibility="Collapsed">
<Rectangle x:Name="PART_SelectionRange" Visibility="Collapsed" />
</Border>
<Thumb x:Name="Thumb" Visibility="Collapsed" />
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I'm trying to add an additional feature to my custom control spinner but I get an error when I attempt to add another command. Anyone who has experience with this, could you possibly explain why this continues to error out. You can find the line in question by just searching for 'MouseUp' which is near the lower 3rd of the XAML. When i attempt to add it, it crashes.
The error:
Exception thrown: 'System.Windows.Markup.XamlParseException' in
PresentationFramework.dll
Numeric.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:btl="clr-namespace:NumericSpinner"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
mc:Ignorable="d">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/NumericSpinner;component/Resources/AllBrushes.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style TargetType="{x:Type btl:NumericSpinnerControl}">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type btl:NumericSpinnerControl}">
<Grid Background="{Binding Path=Background, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" >
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<!--
we use the TemplatedParent binding to get a reference to the control
this template has been applied to, so we can access the property on it
-->
<TextBox Grid.Row="0"
Grid.Column="0"
Width="Auto"
Margin="0,0,1,0"
VerticalAlignment="Center"
BorderThickness="0"
BorderBrush="Transparent"
IsReadOnly="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=IsReadOnly,
Mode=TwoWay}"
Text="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=FormattedValue,
Mode=TwoWay,
NotifyOnTargetUpdated=True,
NotifyOnSourceUpdated=True,
UpdateSourceTrigger=LostFocus,
NotifyOnValidationError=True}"
btl:TextBoxBehavior.SelectAllTextOnFocus ="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=SelectAllOnGotFocus,
Mode=TwoWay}"
>
</TextBox>
<Grid x:Name="grid1"
Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<RepeatButton Grid.Row="0"
Grid.Column="1"
Width="22"
Height="11"
Background="Transparent"
IsEnabled="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=CanIncrement}"
Command="{x:Static btl:NumericSpinnerControl.IncreaseCommand}"
MouseUp="{x:Static btl:NumericSpinnerControl.MouseUpCommand}">
<RepeatButton.Content>
<Rectangle Width="16"
Height="5"
Fill="{StaticResource BrushScrollUp}" />
</RepeatButton.Content>
<RepeatButton.InputBindings>
<MouseBinding MouseAction="RightClick" Command="{x:Static btl:NumericSpinnerControl.SetValueToMaximumCommand}"/>
</RepeatButton.InputBindings>
</RepeatButton>
<RepeatButton Grid.Row="1"
Grid.Column="1"
Width="22"
Height="11"
Background="Transparent"
IsEnabled="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=CanDecrement}"
Command="{x:Static btl:NumericSpinnerControl.DecreaseCommand}">
<RepeatButton.Content>
<Rectangle Width="16"
Height="5"
Fill="{StaticResource BrushScrollDown}" />
</RepeatButton.Content>
<RepeatButton.InputBindings>
<MouseBinding MouseAction="RightClick" Command="{x:Static btl:NumericSpinnerControl.SetValueToMinimumCommand}"/>
</RepeatButton.InputBindings>
</RepeatButton>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Resource dictionary entries should be defined here. -->
</ResourceDictionary>
The commands being called are these:
public static RoutedCommand IncreaseCommand { get; set; }
protected static void OnIncreaseCommand(Object sender, ExecutedRoutedEventArgs e)
{
NumericSpinnerControl control = sender as NumericSpinnerControl;
if (control != null)
{
Console.WriteLine("Pressed");
control.OnIncrease();
}
}
protected void OnIncrease()
{
Value = LimitValueByBounds(Value + Increment, this);
}
public static RoutedCommand MouseUpCommand { get; set; }
protected static void OnMouseUpCommand(Object sender, ExecutedRoutedEventArgs e)
{
NumericSpinnerControl control = sender as NumericSpinnerControl;
if (control != null)
{
Console.WriteLine("mouse up");
}
}
private static void InitializeCommands()
{
// create instances
IncreaseCommand = new RoutedCommand("IncreaseCommand", typeof(NumericSpinnerControl));
MouseUpCommand = new RoutedCommand("MouseUpCommand", typeof(NumericSpinnerControl));
// register the command bindings - if the buttons get clicked, call these methods.
CommandManager.RegisterClassCommandBinding(typeof(NumericSpinnerControl), new CommandBinding(IncreaseCommand, OnIncreaseCommand));
CommandManager.RegisterClassCommandBinding(typeof(NumericSpinnerControl), new CommandBinding(MouseUpCommand, OnMouseUpCommand));
}
This question is a continuation of the pregoing one.( How can I combine some UserControls in SilverLight?)
I have 3 view models with different colour properties.
How can I create elements of User Control with trigger invoke method after pressing the button on the element.
Here is a code of this element that I have upgrade with the trigger action.
<UserControl x:Class="SilverlightApplication14.NodePicture"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:SilverlightApplication14"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">
<Grid x:Name="LayoutRootNodePicture" Height="100" Width="100"
HorizontalAlignment="Center">
<Canvas x:Name="ParentCanvas" Background="{Binding NodeColor}" Width="100" Height="100" >
</Canvas>
<Image HorizontalAlignment="Center"
Source="add.png"
Stretch="Fill"
Width="16"
VerticalAlignment="Top"
Margin="0,0,2,2"
Height="16" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<local:Add />
</i:EventTrigger>
</i:Interaction.Triggers>
</Image>
</Grid>
</UserControl>
And the code with the trigger action
namespace SilverlightApplication14
{
public class Add : TriggerAction<FrameworkElement>
{
protected override void Invoke(object parameter)
{
var vm = AssociatedObject.DataContext as NodeViewModel;
if (vm != null)
{
if (vm.Nodes == null)
{
vm.Nodes = new ObservableCollection<NodeViewModel>();
}
var child = new NodeViewModel { NodeColor = new SolidColorBrush(Color.FromArgb(255, 255, 0, 0)) };
vm.Nodes.Add(child);
}
}
}
}
Updated code:
<Grid>
<Grid.Resources>
<Style x:Key="myStyle" TargetType="ListBoxItem">
<Setter Property="Background" Value="Khaki" />
<Setter Property="Foreground" Value="DarkSlateGray" />
<Setter Property="Margin" Value="5" />
<Setter Property="FontStyle" Value="Italic" />
<Setter Property="FontSize" Value="14" />
<Setter Property="BorderBrush" Value="DarkGray" />
</Style>
</Grid.Resources>
<ListBox ItemsSource="{Binding Nodes}" ItemContainerStyle="{StaticResource myStyle}">
<ListBox.ItemTemplate>
<DataTemplate>
<local:NodePicture DataContext="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</Grid>
Is there a simple (or a right way ) way of doing this?
It is preferable to work with business-logic in view models, whereas triggers are intended for working with UI.
I would change the trigger to a command:
<Button Command="{Binding AddCommand}">
<Button.Template>
<ControlTemplate TargetType="Button">
<Image ... />
</ControlTemplate>
</Button.Template>
</Button>
When a user clicks the button, the AddCommand is invoked. It can be implemented in the view model so:
public class NodeViewModel
{
public NodeViewModel()
{
this.AddCommand = new RelayCommand(obj => { /* do something */ });
}
public RelayCommand AddCommand { get; private set; }
//...
}
The RelayCommand class is one of the possible implementations and it can be downloaded with the MVVM Light framework here.
In WPF, I am creating a simple custom control for my TODO program. It should do the following:
Show up as a ListBox with an Add and Remove button above it.
The Add and Remove buttons should add and remove items from my base class.
I have this working
On pressing F2, I want the list box items to change into a TextBox control.
My main issues/Questions are:
On OnKeyDown, I get the error: This operation is valid only on elements that have this template applied. How do I get around this? This is where I want to press F2, and to be able to make the TextBox visible and Label invisible.
Is there a better way to do this? If my control is a container for buttons AND a text box, should I not be inheriting from ListBox? Should I inherit from Control instead and make it a container?
If so, how do I implement it? Do I basically use the following code in the style, and remove the overrides like OnKeyDown and instead register the KeyDown event for the Textbox? I'll give that a try after this post but let me know if you have any advice.
I had something close working before, in the following code, but now I want this moved from my main Window XAML to the custom control code, and I want to be able to edit on button press:
<!-- In my MainWindow.XAML -->
<TaskDashControls:ListBoxWithAddRemove x:Name="listBoxItems" Grid.Row="1" Grid.Column="3" Grid.RowSpan="3"
ItemsSource="{Binding}">
<TaskDashControls:ListBoxWithAddRemove.ItemTemplate>
<DataTemplate>
<DockPanel>
<Button DockPanel.Dock="Left" Click="SelectItemClick">SELECT</Button>
<TextBlock x:Name="LabelDescription" Visibility="Visible" DockPanel.Dock="Left" Text="{Binding Description}" Height="25" Width="150" />
<TextBox x:Name="EditableDescription" Visibility="Collapsed" DockPanel.Dock="Left" Text="{Binding Description}" Height="25" Width="150" />
<Button DockPanel.Dock="Left" Click="EditTaskItemClick">EDIT</Button>
</DockPanel>
</DataTemplate>
</TaskDashControls:ListBoxWithAddRemove.ItemTemplate>
</TaskDashControls:ListBoxWithAddRemove>
I have now removed the DataTemplate, to move it over to the custom control:
<!-- In my MainWindow.XAML -->
<TaskDashControls:ListBoxWithAddRemove x:Name="listBoxItems" Grid.Row="1" Grid.Column="3" Grid.RowSpan="3"
ItemsSource="{Binding}"/>
Here is the custom control in Generic.XAML:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TaskDash.Controls">
<SolidColorBrush x:Key="WindowBackgroundBrush" Color="#FFF" />
<SolidColorBrush x:Key="SolidBorderBrush" Color="#888" />
<SolidColorBrush x:Key="DisabledForegroundBrush" Color="#888" />
<SolidColorBrush x:Key="DisabledBackgroundBrush" Color="#EEE" />
<SolidColorBrush x:Key="DisabledBorderBrush" Color="#AAA" />
<Style TargetType="{x:Type TextBox}">
<Setter Property="Margin" Value="2" />
</Style>
<Style x:Key="{x:Type local:ListBoxWithAddRemove}" TargetType="{x:Type local:ListBoxWithAddRemove}">
<Setter Property="Margin" Value="3" />
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="MinWidth" Value="120"/>
<Setter Property="MinHeight" Value="20"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!--<Button Grid.Column="0" Grid.Row="0" x:Name="DeleteButton"
Click="DeleteControlClick">Delete</Button>
<Button Grid.Column="1" Grid.Row="0" x:Name="AddButton"
Click="AddControlClick">Add</Button>-->
<Button Grid.Column="0" Grid.Row="0" x:Name="DeleteButton">Delete</Button>
<Button Grid.Column="1" Grid.Row="0" x:Name="AddButton">Add</Button>
<Border
Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2"
Name="Border"
Background="{StaticResource WindowBackgroundBrush}"
BorderBrush="{StaticResource SolidBorderBrush}"
BorderThickness="1"
CornerRadius="2">
<ScrollViewer
Margin="0"
Focusable="false">
<StackPanel Margin="0" IsItemsHost="True" />
</ScrollViewer>
<!--<ListBox ItemTemplate="{TemplateBinding ItemTemplate}">
<DataTemplate>
<DockPanel>
<TextBlock x:Name="LabelDescription" Visibility="Visible" DockPanel.Dock="Left" Text="{Binding Description}" Height="25" Width="150" />
<TextBox x:Name="EditableDescription" DockPanel.Dock="Left" Text="{Binding Description}" Height="25" Width="150" />
</DockPanel>
</DataTemplate>
</ListBox>-->
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Here is my custom control class
using System;
using System.Windows;
using System.Windows.Controls;
namespace TaskDash.Controls
{
[TemplatePart(Name = "Text", Type = typeof(TextBox))]
[TemplatePart(Name = "LabelText", Type = typeof(TextBlock))]
public class TextBoxWithDescription : Control
{
static TextBoxWithDescription()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TextBoxWithDescription), new FrameworkPropertyMetadata(typeof(TextBoxWithDescription)));
}
public TextBoxWithDescription()
{
LabelText = String.Empty;
Text = String.Empty;
}
public static readonly DependencyProperty LabelTextProperty =
DependencyProperty.Register("LabelText", typeof(string), typeof(TextBoxWithDescription),
new PropertyMetadata(string.Empty, OnLabelTextPropertyChanged));
private static void OnLabelTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
public string LabelText
{
get { return GetValue(LabelTextProperty).ToString(); ; }
set { SetValue(LabelTextProperty, value); }
}
// http://xamlcoder.com/cs/blogs/joe/archive/2007/12/13/building-custom-template-able-wpf-controls.aspx
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(TextBoxWithDescription),
new UIPropertyMetadata(null,
new PropertyChangedCallback(OnTextChanged)
));
private static void OnTextChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
TextBoxWithDescription textBox = o as TextBoxWithDescription;
if (textBox != null)
textBox.OnTextChanged((String)e.OldValue, (String)e.NewValue);
}
protected virtual void OnTextChanged(String oldValue, String newValue)
{
// fire text changed event
this.Text = newValue;
this.RaiseEvent(new RoutedEventArgs(TextChangedEvent, this));
}
public string Text
{
get { return GetValue(TextProperty).ToString(); }
set { SetValue(TextProperty, value); }
}
public static readonly RoutedEvent TextChangedEvent =
EventManager.RegisterRoutedEvent("TextChanged",
RoutingStrategy.Bubble,
typeof(RoutedEventHandler),
typeof(TextBoxWithDescription));
public event RoutedEventHandler TextChanged
{
add { AddHandler(TextChangedEvent, value); }
remove { RemoveHandler(TextChangedEvent, value); }
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
//var textBlock = (TextBlock)this.Template.FindName("LabelText", this);
//if (textBlock != null) textBlock.Text = this.LabelText;
//var textBox = (TextBox)this.Template.FindName("Text", this);
//if (textBox != null) textBox.Text = this.Text;
}
}
}
I would create a class for TODO with Properties: String Desc, Visibility txtBox, Visibility txtBlock. Then items source for the TaskDashControls is List TODO. In xaml you can bind the visibilty property. In the TODO class you can control that when one is visible the other is not.