I'm trying to assign different increment values to different fields of an object. For example, consider a class has who has int1 and int2, and when I set ShowAdvancedOptions to true for my PropertyGrid, integer up down buttons are put in the textbox with no problems. But I want to be able to edit how much the numbers are incremented individually. Is there a way I can ahcieve this?
Edit:
Here is the code:
public MainWindow()
{
InitializeComponent();
Sample or = new Sample();
pg.SelectedObject = or;
pg.ShowAdvancedOptions = true;
}
MainWindow.xaml:
<Window
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:WpfApp1"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid" x:Class="WpfApp1.MainWindow"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<xctk:PropertyGrid x:Name="pg" HorizontalAlignment="Left" Margin="328,70,0,0" VerticalAlignment="Top" Height="275" Width="341"/>
</Window>
and the Sample class:
public class Sample
{
public enum SampleEnum
{
A,B,C,D,E
}
#region private fields
private SampleEnum _SampleEnum;
private int _Value;
#endregion
#region Public Properties
[Category("Sample")]
[DisplayName("Sample Value")]
[DefaultValue(3)]
public int Value { set; get; }
#endregion
}
You could define a custom EditorTemplate per property:
<xctk:PropertyGrid x:Name="pg">
<xctk:PropertyGrid.EditorDefinitions>
<xctk:EditorDefinition>
<xctk:EditorDefinition.PropertiesDefinitions>
<xctk:PropertyDefinition Name="int1" />
</xctk:EditorDefinition.PropertiesDefinitions>
<xctk:EditorDefinition.EditorTemplate>
<DataTemplate>
<xctk:PropertyGridEditorIntegerUpDown Increment="10" Value="{Binding Value}" />
</DataTemplate>
</xctk:EditorDefinition.EditorTemplate>
</xctk:EditorDefinition>
</xctk:PropertyGrid.EditorDefinitions>
</xctk:PropertyGrid>
In the above sample markup, the int1 property is incremented by 10 instead of 1 which is the default value.
Related
The following code works by having the combobox populated by the C# code behind at run-time.
I would like to populate the user control combos declaratively from XAML, similar to how the description label is populated.
This code is just for my personal use, so I won't be using complex MVVM models. I'd ideally like a solution that passes string arrays from the main XAMLcode, to the user control as I'd like to know how to do that.
Thanks in advance :-)
//Main Window.xaml
<Window
x:Class="WpfApp1.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:WpfApp1"
mc:Ignorable="d"
Title="Car Details"
SizeToContent="WidthAndHeight">
<StackPanel>
<local:myControl
x:Name="myMake"
myDescription="Make" />
<local:myControl
x:Name="myModel"
myDescription="Model" />
<local:myControl
x:Name="myYear"
myDescription="Year" />
</StackPanel>
</Window>
//MainWindow.xaml.cs
using System.Windows;
namespace WpfApp1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
//myMake is the name of a specific myControl
//myOption is the name of the combo within myControl
myMake.myOptions.ItemsSource = new string[] { "Ford", "Toyota" };
}
}
}
//myControl.xaml
<UserControl
x:Class="WpfApp1.myControl"
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:WpfApp1"
mc:Ignorable="d">
<StackPanel>
<Label
Content="{Binding myDescription,FallbackValue=description}"
/>
<ComboBox
x:Name="myOptions"
Width="120" />
</StackPanel>
</UserControl>
//myControl.xaml.cs
using System.Windows;
using System.Windows.Controls;
namespace WpfApp1
{
public partial class myControl : UserControl
{
public myControl()
{
InitializeComponent();
this.DataContext = this;
}
public string myDescription
{
get { return (string)GetValue(myDescriptionProperty); }
set { SetValue(myDescriptionProperty, value); }
}
public static readonly DependencyProperty myDescriptionProperty = DependencyProperty.Register("myDescription", typeof(string), typeof(myControl), new PropertyMetadata(null));
}
}
You can declare an array of string in xaml like this:
<x:Array xmlns:s="clr-namespace:System;assembly=mscorlib" x:Key="myStringArray" Type="{x:Type s:String}">
<s:String>Ford</s:String>
<s:String>Toyota</s:String>
</x:Array>
Source: this answer
So your view becomes:
<Window x:Class="WpfApp1.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:WpfApp1"
mc:Ignorable="d"
Title="Car Details" SizeToContent="WidthAndHeight">
<Window.Resources>
<!--Declaration of an array of string which is added to the ressources of the window-->
<x:Array xmlns:s="clr-namespace:System;assembly=mscorlib" x:Key="myStringArray" Type="{x:Type s:String}">
<s:String>Ford</s:String>
<s:String>Toyota</s:String>
</x:Array>
</Window.Resources>
<StackPanel>
<!--We get the array from the ressource by calling "StaticResource" with the key of the element to obtain-->
<local:myControl
x:Name="myMake" myDescription="Make" ArrayItemsSource="{StaticResource myStringArray}" />
<!--Do the same for the other usercontrol -->
<local:myControl
x:Name="myModel"
myDescription="Model" />
<local:myControl
x:Name="myYear"
myDescription="Year" />
</StackPanel>
In your usercontrol, you should not use this.DataContext = this; as this is bad practice since it prevents your usercontrol from inheriting the datacontext of the view (I know you are not planning on using MVVM but I think this should still be mentioned for other readers).
So because the datacontext is not the control, the bindings in the xaml of the usercontrol have to be modified like this: {Binding ElementName=myControlName, Path=theNameOfThePropertyIwantToBind}
I created a new dependency property to pass the array of string from the view so the usercontrol becomes:
Xaml:
<UserControl x:Class="WpfApp1.myControl"
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:WpfApp1" x:Name="myControlName"
mc:Ignorable="d">
<StackPanel>
<Label
Content="{Binding ElementName=myControlName, Path=myDescription,FallbackValue=description}"
/>
<ComboBox
x:Name="myOptions" ItemsSource="{Binding ElementName=myControlName, Path=ArrayItemsSource}"
Width="120" />
</StackPanel>
The code behind:
public partial class myControl : UserControl
{
public myControl()
{
InitializeComponent();
//Bad practice
//this.DataContext = this;
}
public string myDescription
{
get { return (string)GetValue(myDescriptionProperty); }
set { SetValue(myDescriptionProperty, value); }
}
public string[] ArrayItemsSource
{
get { return (string[])GetValue(ArrayItemsSourceProperty); }
set { SetValue(ArrayItemsSourceProperty, value); }
}
public static readonly DependencyProperty myDescriptionProperty = DependencyProperty.Register("myDescription", typeof(string), typeof(myControl), new PropertyMetadata(null));
public static readonly DependencyProperty ArrayItemsSourceProperty = DependencyProperty.Register(nameof(ArrayItemsSource), typeof(string[]), typeof(myControl), new PropertyMetadata(null));
}
So I have a user interface which has several controls which I want to persist. One of these controls is a button that is supposed to swap between a view and an edit mode. Each of these will have many controls in them that will need to be accessible later on. My main page is defined as follows, with irrelevant stuff stripped down of course.
MapView.xaml
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TripPhotoMapper"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Maps="using:Windows.UI.Xaml.Controls.Maps"
x:Class="TripPhotoMapper.MapView"
mc:Ignorable="d">
<Grid x:Name="grid_main">
<Maps:MapControl x:Name="map_main" MapTapped="MapUserTapped"/>
<StackPanel x:Name="stack_edit_mode">
<Border Tapped="ButtonEditMode">
<TextBlock Text="Edit Mode"/>
</Border>
</StackPanel>
<Grid x:Name="grid_swap_interface">
here is where I want the swapable interfaces
</Grid>
</Grid>
</Page>
MapView.xaml.cs
namespace TripPhotoMapper
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MapView : Page
{
private EditMode _mode_edit;
private ViewMode _mode_view;
private Control _mode_current;
public MapView()
{
this.InitializeComponent();
_mode_edit = new EditMode();
_mode_view = new ViewMode();
_mode_current = _mode_view;
grid_swap_interface.Children.Add(_mode_current);
}
public static class GlobalVars
{
...
//this keeps track on if we are in edit mode
public static bool glo_edit_mode = false;
}
...
private void MapUserTapped(MapControl sender, MapInputEventArgs args)
{
...
//this is the problem
ViewMode.txtblc_view_mode.Text = "hi";
}
//editing controls
private void ButtonEditMode(object sender, TappedRoutedEventArgs e)
{
grid_swap_interface.Children.Clear();
if (GlobalVars.glo_edit_mode == false)
{
_mode_current = _mode_edit;
}
else
{
_mode_current = _mode_view;
}
grid_swap_interface.Children.Add(_mode_current);
}
}
}
I then have two other very barebones xaml files for the two interfaces.
EditMode.xaml
<UserControl
x:Class="TripPhotoMapper.EditMode"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TripPhotoMapper"
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="400">
<Grid>
<Button/>
</Grid>
</UserControl>
ViewMode.xaml
<UserControl
x:Class="TripPhotoMapper.ViewMode"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TripPhotoMapper"
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="400">
<Grid>
<TextBlock x:Name="txtblc_view_mode" Text="view mode"/>
</Grid>
</UserControl>
I haven't touched the C# for either of these two additional xaml's yet. So they're just like this.
EditMode.xaml.cs
namespace TripPhotoMapper
{
public sealed partial class EditMode : UserControl
{
public EditMode()
{
this.InitializeComponent();
}
}
}
So I've figured out how to swap between the two interfaces without any issue; the button and textblock do both appear as they should. However, I included (for testing) a function to change the text in txtblc_view_mode to "hi", but I'm given the following error:
'ViewMode.txtblc_view_mode' is inaccessible due to its protection level
I'm incredibly new to splitting up files like this and I can't figure out how to fix it. I've found something mentioned in a few posts
x:FieldModifier="public"
but I don't know where to put it. Could anyone help me? Once the interfaces are properly split up, a lot of controls in each will have to be modified in code and thus I'll need to fix this problem.
Can't try this for now but you can check it out.
Add/modify the following code in your ViewMode cs:
public sealed partial class ViewMode : UserControl
{
public static ViewMode Current { get; private set; }
public ViewMode()
{
this.InitializeComponent();
Current = this;
}
}
And maintain the x:FieldModifier="public" in your desired control (TextBlock) to be edited/modified.
<TextBlock x:Name="txtblc_view_mode" x:FieldModifier="public" Text="view mode"/>
On EditMode cs, add in your methods:
public void ChangeTxtBlockText()
{
TextBlock tb = ViewMode.Current.txtblc_view_mode as TextBlock;
if (tb != null)
{
tb.Text = "Hi";
}
}
I have one dll which contains the wpf user control.
I have one wpf window in another wpf project which contains the above user control in that.
I have two public properties in wpf user control.
I want to set those properties from the wpf window in which wpf user control is added.
I have tried to do it using dependency property as follows :
TestUserControl.xaml :-
<UserControl x:Class="TestDependencyProperty.TestUserControl"
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">
<Grid>
<Label Content="test property" x:Name="lblTestProperty"/>
</Grid>
</UserControl>
TestUserControl.xaml.cs :-
using System.ComponentModel;
using System.Windows;
namespace TestDependencyProperty
{
/// <summary>
/// Interaction logic for TestUserControl.xaml
/// </summary>
public partial class TestUserControl
{
public TestUserControl()
{
InitializeComponent();
SetLabelText();
}
private void SetLabelText()
{
lblTestProperty.Content = TestProperty;
}
public static readonly DependencyProperty TestDependencyProperty =
DependencyProperty.Register("TestProperty",
typeof(string),
typeof(TestUserControl));
[Bindable(true)]
public string TestProperty
{
get
{
return (string)this.GetValue(TestDependencyProperty);
}
set
{
this.SetValue(TestDependencyProperty, value);
}
}
}
MainWindow.xaml :-
<Window x:Class="TestDependencyProperty.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"
xmlns:local="clr-namespace:TestDependencyProperty"
>
<Grid>
<local:TestUserControl x:Name="ucTest" TestProperty="HelloWorld"/>
</Grid>
</Window>
I am expecting a label with content "HelloWorld".
So can anybody tell me how to do it ?
Thanks.
User Control XAML:
<UserControl x:Class="TestDependencyProperty.TestUserControl"
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:WpfApplication3"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Label Content="{Binding TestProperty}" x:Name="lblTestProperty"/>
</Grid>
</UserControl>
User Control Code:
public partial class TestUserControl : UserControl
{
public TestUserControl()
{
InitializeComponent();
}
public static readonly DependencyProperty TestDependencyProperty =
DependencyProperty.Register("TestProperty",
typeof(string),
typeof(TestUserControl));
[Bindable(true)]
public string TestProperty
{
get
{
return (string)this.GetValue(TestDependencyProperty);
}
set
{
this.SetValue(TestDependencyProperty, value);
}
}
}
You do not need SetLabelText();
Window Hosting User Control
<local:TestUserControl TestProperty="Test Text" x:Name="MyNewUserControl" />
in code behind if needed:
MyNewUserControl.TestProperty="New Value";
Dependency Properties have change notification built in to them so once a property is bound to them it will automatically get updated when the property does.
Consider following XAML:
<Window x:Class="WpfApplication1.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">
<StackPanel>
<TextBlock Text="{Binding Dic[foo]}" />
<Button Content="test" Click="Button_Click" />
</StackPanel>
</Window>
And Backing code:
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public Dictionary<string, string> Dic { get; set; }
public MainWindow()
{
InitializeComponent();
Dic = new Dictionary<string, string>();
Dic.Add("foo", "bar");
DataContext = this;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// Doesn't work :(
Dic["foo"] = "YEAH!";
}
}
}
Here TextBlock properly binds to dictionary item "foo". But how to make it to update when its value is changed?
You need to raise a change notification for the indexer using Binding.IndexerName as property name, you might want to encapsulate that in a new class inheriting or managing Dictionary.
have your dictionnary be a dictionnary(of string, DescriptionObject) Where DescriptionObject has a notifying string property, implements PropertyChanged and has a ToString override.
Then you add (foo, fooDescription) to your dictionnary. If you change fooDescription in your ButtonClick handler, the TextBlock will change too.
You need to add indexer to your code like that:
private Dictionary<string, string> Dic { get; set; }
public string this[string key]
{
get { return Dic[key]; }
set
{
if(key != null && Dic[key] != value)
Dic[key] = value;
OnPropertyChanged("Item[" + key + "]");
}
}
Then, in the xaml you make binding to the indexer, and when the item change it will be notify:
<Window x:Class="WpfApplication1.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">
<StackPanel>
<TextBlock Text="{Binding [foo]}" />
<Button Content="test" Click="Button_Click" />
</StackPanel>
</Window>
Here is my user control(MonthCal)'s code behind.
public partial class MonthCal : UserControl
{
public DayOfWeek StartDayOfWeek { get { return (DayOfWeek)GetValue(StartDayOfWeekProperty); } set { SetValue(StartDayOfWeekProperty, value); } }
public static readonly DependencyProperty StartDayOfWeekProperty = DependencyProperty.Register("StartDayOfWeek", typeof(DayOfWeek), typeof(MonthCellHeader), new UIPropertyMetadata(DayOfWeek.Sunday, StartDayOfWeek_PropertyChanged));
//...
}
and also, here is a xaml of the MonthCal.
<UserControl x:Class="GCDR.MonthCal"
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">
<!-- ... -->
</UserControl>
And so, How can I set the 'StartDayOfWeek' dependency property in xaml? as you guys know, the following code is impossible:
<UserControl ...
StartDayOfWeek="Sunday">
</UserControl>
Please give me a help.
You can not use the dependency property in markup of the UserControl but you can use it when you place instance of the user control somewhere like so:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1">
<Grid>
<local:UserControl1 local:StartDayOfWeek="Friday" />
</Grid>
</Window>
With in your user control you can bind some other property to your dependency property like so:
<UserControl x:Class="WpfApplication1.UserControl1"
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:WpfApplication1"
mc:Ignorable="d" >
<Grid>
<Label Content="{Binding RelativeSource={RelativeSource AncestorType=local:UserControl1},Path=StartDayOfWeek}" />
</Grid>
</UserControl>
Why you cannot set StartDayOfWeek is that UserControl in XAML does not have StartDayOfWeek dependency property, in other word UserControl type is not MonthCal type.
As, in XAML, UserControl is base class of UserControl1, you can define MonthCal inherited UserControl and then declare MonthCal in XAML.
XAML
<local:MonthCal x:Class="WpfApplication1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication1" Title="MainWindow"
Height="350" Width="525"
StartDayOfWeek="Monday">
<Grid></Grid>
</local:MonthCal>
Codebehinde
namespace WpfApplication1
{
public class MonthCal : Window
{
public DayOfWeek StartDayOfWeek { get { return (DayOfWeek)GetValue(StartDayOfWeekProperty); } set { SetValue(StartDayOfWeekProperty, value); } }
public static readonly DependencyProperty StartDayOfWeekProperty =
DependencyProperty.Register("StartDayOfWeek", typeof(DayOfWeek), typeof(MonthCal), new UIPropertyMetadata(DayOfWeek.Sunday, StartDayOfWeek_PropertyChanged));
private static void StartDayOfWeek_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
}
public partial class MainWindow : MonthCal
{
public MainWindow()
{
InitializeComponent();
}
}
}