I want to use xaml to build my workflow like this to split the workflow design and functions.
<Command x:Class="MyCommand">
<Step1 Name="">
<Step2 />
</Step1>
</Command/>
it works.
but when I want to get a value may be updated, i must write a event:
<Command x:Class="MyCommand">
<Step1 GetName="OnGetName">
<Step2 />
</Step1>
</Command/>
void OnGetName(out string name){name = "xxx";}
I think wpf's binding is very well for me ,but sine there are no window, my classes are not inherit from control, It cannot work, event I make my classes inherit from DependencyObject.
Is there any way to import a binding like method?
I update my question as maybe a complete new question.
My real request is use xaml binding without window.
at beginning, I don't want to inherit from Control or FrameworkElement. bug I find it is impossible.
now I update my code to inherit from FrameworkElement, it can work by write binding, but event not with xaml.
public class Command : FrameworkElement
{
public static readonly DependencyProperty Test1Property = DependencyProperty.Register(
nameof(Test1), typeof(string), typeof(UserControl1), new PropertyMetadata(default(string)));
public string Test1
{
get { return (string)GetValue(Test1Property); }
set { SetValue(Test1Property, value); }
}
public static readonly DependencyProperty Test2Property = DependencyProperty.Register(
nameof(Test2), typeof(string), typeof(UserControl1), new PropertyMetadata(default(string)));
public string Test2
{
get { return (string)GetValue(Test2Property); }
set { SetValue(Test2Property, value); }
}
}
I add a window:
<Window x:Class="WpfApp2.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:WpfApp2"
mc:Ignorable="d" x:Name="Main"
DataContext="{x:Reference Main}"
Title="MainWindow" Height="450" Width="800">
<Grid>
<local:UserControl1 x:Name="Control" Test1="{Binding TestStr, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"></local:UserControl1>
</Grid>
</Window>
and init the Test2 binding by code:
public MainWindow()
{
InitializeComponent();
var binding = new Binding("TestStr")
{
Source = this,
};
BindingOperations.SetBinding(Control, UserControl1.Test2Property, binding);
TestStr = "XXS";
MessageBox.Show($"ONLoad: Test1: {Control.Test1}, Test2: {Control.Test2}");
}
then if I new the MainWindow, without Show(), I get the MessageBox show
Test1:, Test2:XXS
I want to find a way to make the xaml binding work before show()!
Related
I have a WPF window which I have changed its borders, title bar and buttons for a custom one. Separately in a ResourceDictionary I have defined the Style that I want to apply to my WPF window.
Then I bind that style to my WPF Window using below line of code:
Style="{DynamicResource CustomWindowStyle}"
Please see all my code posted in another thread that I created to ask for other things. Refer to this thread to see the code (I want to avoid repeating here again).
Now what I am trying to do is to create some custom properties (MyCustomProperty01, MyCustomProperty02) to that WPF Window, some like below:
myDialogView.xaml:
<Window x:Class="myApp.Views.myDialogView"
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:v="clr-namespace:myApp.Views"
xmlns:vm="clr-namespace:myApp.ViewModels"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
ResizeMode="NoResize"
SizeToContent="WidthAndHeight"
Style="{StaticResource CustomWindowStyle}"
WindowStyle="None"
MyCustomProperty01 = "true"
MyCustomProperty02 = "true">
...and then in the code-behind of this WPF window (xaml.cs) I want to define those dependency properties MyCustomProperty01 and MyCustomProperty02, the ones you see above in the code snippet for the Window.
So I create those dependency properties in the code-behind as below.
myDialogView.xaml.cs (code-behind):
namespace myApp.Views
{
public partial class myDialogView: Window
{
public myDialogView()
{
InitializeComponent();
}
public static readonly DependencyProperty MyCustomProperty01Property =
DependencyProperty.Register("MyCustomProperty01",
typeof(bool),
typeof(myDialogView),
new FrameworkPropertyMetadata(false));
public bool MyCustomProperty01
{
get => (bool)GetValue(MyCustomProperty01Property );
set => SetValue(MyCustomProperty01Property , value);
}
public static readonly DependencyProperty MyCustomProperty02Property =
DependencyProperty.Register("MyCustomProperty02",
typeof(bool),
typeof(myDialogView),
new FrameworkPropertyMetadata(false));
public bool MyCustomProperty02
{
get => (bool)GetValue(MyCustomProperty02Property );
set => SetValue(MyCustomProperty02Property , value);
}
}
}
So when I start typing these dependency properties MyCustomProperty01 and MyCustomProperty01 for the window in the xaml view, intellisense looks like it is not recognizing those dependency properties. So what am I doing wrong? Could some tell me how I can achieve this with some code snippet?
You need to registerattached for this to work.
I'm not 100% sure why, I just know it won't work with the usual dependency property.
I think it's because it's in a window tag and it's "really" a myDialogView causes the issue.
Here's an example attached property I have:
public static readonly DependencyProperty TakeMapPictureProperty =
DependencyProperty.RegisterAttached(
"TakeMapPicture",
typeof(bool),
typeof(MainWindow),
new FrameworkPropertyMetadata(false
, new PropertyChangedCallback(TakeMapPictureChanged)
));
private static async void TakeMapPictureChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
public static void SetTakeMapPicture(UIElement element, bool value)
{
element.SetValue(TakeMapPictureProperty, value);
}
public static bool GetTakeMapPicture(UIElement element)
{
return (bool)element.GetValue(TakeMapPictureProperty);
}
And in the window tag
local:MainWindow.TakeMapPicture="{Binding CaptureMap}"
Where you might want to use the one dependency property in several user controls or windows, you can define the attached properties in a separate class. There are a couple of ways to do this but the one I prefer looks like:
public class MainWin : DependencyObject
{
public static readonly DependencyProperty MapFileProperty = DependencyProperty.RegisterAttached(
"MapFile",
typeof(string),
typeof(MainWin),
new FrameworkPropertyMetadata(string.Empty
, new PropertyChangedCallback(MapFileChanged)
));
And that is used inside a window tag:
local:MainWin.MapFile="{Binding Path=MapFile}"
You are trying to set the property on the wrong element (locally/attribute syntax):
<Window ... MyCustomProperty01="True" />
Of course, Window does not have a MyCustomProperty01 property.
But myDialogView has this property.
To set this property, either use a Style:
<Window>
<Window.Resources>
<Style TargetType="myDialogView">
<Setter Property="MyCustomProperty01" Value="True" />
</Style>
</Window.Resources>
</Window>
Or set it locally on the proper myDialogView element. But you would have to create a derived type (e.g., myExtendedDialogView), so that you can define myDialogView (the base type) as the root element.
Note how the root element is always the base type of the actual extending type: for example <Window /> of MainWindow or <UserControl /> of MyUserControl or <Page /> of MyPage or <Application /> of App.
Specify the partial class (the derived type that provides the code-behind file) using the x:Class directive on the root element:
<myDialogView x:Class="myExtendedDialogView"
MyCustomProperty01="True">
</myDialogView >
// Define the extended class as partial (with code-behind)
// and the base class that contains the custom properties as a simple class (no code-behind)
partial class myExtendedDialogView : myDialogView
{
public myExtendedDialogView() => InitializeComponent();
}
// Base class used as XAML root element.
// This type has no code-behind file (not partial)
class myDialogView : Window
{
// Dependency properties
}
I 'm trying to do something really simple: I have a UserControl, where I want to pass a simple string parameter.
WPF MessagePage.xaml
<Page
x:Class="MuchroomPhone.MessagePage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MuchroomPhone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
//...
<PivotItem Header="Nouveaux">
<local:MessageUC MessType="new"/>
</PivotItem>
<PivotItem Header="Lus" >
<local:MessageUC MessType="read"/>
</PivotItem>
<PivotItem Header="Envoyés" >
<local:MessageUC MessType="send"/>
</PivotItem>
<PivotItem Header="Tous" >
<local:MessageUC MessType="all"/>
</PivotItem>
//...
I want to get the MessType from the code behind of the MessageUC.
eg. : I want to get the string "new" in the MessageUC.xaml.cs
I've tried that so far:
MessageUC.xaml
<UserControl
x:Class="MuchroomPhone.MessageUC"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MuchroomPhone"
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">
//I don't think the content of the UC is important for my issue, but if you wanted to I can give it too.
MessageUC.xaml.cs
public sealed partial class MessageUC : UserControl
{
public string _messType;
public string MessType
{
get{ return _messType;}
set{this._messType = value;}
}
public ObservableCollection<Message> listMessages { get; set; }
public MessageUC()
{
this.InitializeComponent();
Debug.WriteLine(MessType);
this.fetchUserData();
}
But the MessType string is empty...
Any ideas how to achieve that?
PS: I think there should be a way less verbose way for do that, so if you know a "simple" trick, would be great!
Thanks
EDIT: So If I use a simple property, it's should work? Cause I still have null on MessType...
I've also tried with a Dependency Property, and MessType is an empty string.
EDIT 2: I think I understand what is wrong. Actually MessType doesn't exist on MessageUC.xaml. So the code behind can't find it. Perhaps isn it possible to just pass variable to my Page MessagePage.xaml directly to the User Control MessageUC?
all you need is move fetchUserData to loaded event:
public sealed partial class MessageUC : UserControl
{
public string MessType { get; set; }
public MessageUC()
{
InitializeComponent();
Debug.Writeline(MessType); //null
Loaded += MessageUC_Loaded;
}
public void MessageUC_Loaded(object sender, EventArgs e)
{
Debug.Writeline(MessType); //new
this.fetchUserData();
}
}
DependencyProperty is not needed! Your original code doesn't work, because ctor in invoked before the property is set. DependecyProperty does not solve this, but enables databinding, styling, animating of the property.
You only need a DependencyProperty if you want to data bind to it. In your case you can just use a normal property.
This is a set of instructions that should work. However you didn't show the definition of your control so the code below may need some modifications and adjustments.
So start with registering a dependency property:
public static readonly DependencyProperty _messTypeProperty =
DependencyProperty.Register("_messType", typeof(String),
typeof(MessageUC), new FrameworkPropertyMetadata(string.Empty));
public String _messType
{
get { return GetValue(_messTypeProperty).ToString(); }
set { SetValue(_messTypeProperty, value); }
}
Add a name to your control in XAML:
<UserrControl x:Class="myNamespace.MessageUC"
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"
x:Name="MyUserControl">
In the XAML definition of your MessageUC control, in the code where you implement MessType bind it to the property in the code behind. Point to your control using the name you added to the control definition:
MessType="{Binding Path=_messType, ElementName=MyUserControl}"
I have read through a few articles on this and I can't see what im doing wrong here could anyone help :)
I have a UserControl called CreateRuleItemView I want to add a Dependency Property on here that I can bind my ViewModel too. So far I have.
public partial class CreateRuleItemView : UserControl
{
public CreateRuleItemView()
{
InitializeComponent();
}
public Boolean ShowEditTablePopup
{
get
{
return (Boolean)this.GetValue(ShowEditTablePopupProperty);
}
set
{
this.SetValue(ShowEditTablePopupProperty, value);
}
}
public static readonly DependencyProperty ShowEditTablePopupProperty = DependencyProperty.Register("ShowEditTablePopup", typeof(Boolean), typeof(CreateRuleItemView), new PropertyMetadata(null, OnShowEditTablePopupChanged));
private static void OnShowEditTablePopupChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
}
}
If I then try to access the property in the User Control Xaml I get:
<UserControl x:Class="Views.Setup.CreateRuleItemView"
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"
d:DataContext="{d:DesignInstance Type=vm:CreateRuleItemViewModel, IsDesignTimeCreatable=False}"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400" ShowEditTablePopup="{Binding DataContext.ShowEditTablePopup}" >
Error 1 The member "ShowEditTablePopup" is not recognized or is not accessible.
Error 3 The property 'ShowEditTablePopup' does not exist on the type 'UserControl'
Error 2 The property 'ShowEditTablePopup' was not found in type 'UserControl'.
Edit 1:
Ok Managed to get around this by adding the binding in the code behind on my Main window where i setup my view.
Setup.CreateRuleItemView v = new Setup.CreateRuleItemView();
BindingOperations.SetBinding(v, CreateRuleItemView.EditTablePopupProperty, new Binding("EditTablePopup"));
You won't be able to achieve this with a UserControl (I've just tried replacing the <UserControl... partial declaration in XAML with <local:CreateRuleItemView when recreating the code locally, but this results in a circular reference and thus won't compile/will potentially result in a XamlParseException). I'd write a control inheriting from ContentControl to which you can add the property and template it instead (I did this with WPF so the namespaces may differ, otherwise the code will work):
using System;
using System.Windows;
using System.Windows.Controls;
namespace DepPropTest
{
/// <summary>
/// Description of CreateRuleItemView.
/// </summary>
public class CreateRuleItemView : ContentControl
{
public CreateRuleItemView()
{
}
public static readonly DependencyProperty ShowEditTablePopupProperty =
DependencyProperty.Register("ShowEditTablePopup", typeof (bool), typeof (CreateRuleItemView), new PropertyMetadata());
public bool ShowEditTablePopup
{
get { return (bool) GetValue(ShowEditTablePopupProperty); }
set { SetValue(ShowEditTablePopupProperty, value); }
}
}
}
Then you can use it as follows (this example uses WPF by the way, hence Window being the parent control):
<Window x:Class="DepPropTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DepPropTest"
Title="DepPropTest" Height="300" Width="300">
<local:CreateRuleItemView Width="300"
Height="300"
ShowEditTablePopup="True">
<local:CreateRuleItemView.Template>
<ControlTemplate>
<!-- define your control's visual appearance... -->
</ControlTemplate>
</local:CreateRuleItemView.Template>
<TextBox Text="Some content for your view" />
</local:CreateRuleItemView>
</Window>
My end goal is to expose the Text value of a TextBox that I have in a UserControl, from the UserControl's call in XAML.
<my:UserControl SetCustomText="Blah blah this is variable">
would render the UserControl with that TextBox's text filed in.
I've been working at it using various examples but I always end up with "The Property SetCustomText was not found in type UserControl"
Example of how you can do this:
<UserControl x:Class="Test.UserControls.MyUserControl1"
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"
Name="control">
<Grid>
<!-- Text is being bound to outward representative property -->
<TextBox Text="{Binding MyTextProperty, ElementName=control}"/>
</Grid>
</UserControl>
public partial class MyUserControl1 : UserControl
{
// The dependency property which will be accessible on the UserControl
public static readonly DependencyProperty MyTextPropertyProperty =
DependencyProperty.Register("MyTextProperty", typeof(string), typeof(MyUserControl1), new UIPropertyMetadata(String.Empty));
public string MyTextProperty
{
get { return (string)GetValue(MyTextPropertyProperty); }
set { SetValue(MyTextPropertyProperty, value); }
}
public MyUserControl1()
{
InitializeComponent();
}
}
<uc:MyUserControl1 MyTextProperty="Text goes here"/>
I have a UserControl in my Silverlight application and for some reason, the DependencyProperty of a UserControl is not set if I bind it to a value in the view model. I spent several hours of debugging in a trial-and-error fashion now and I'm all out of ideas what to try next.
I can reproduce the issue in a new Silverlight project with
MainPage.xaml
<UserControl x:Class="SilverlightApplication1.MainPage"
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:SilverlightApplication1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<StackPanel>
<local:MyCtrl HeaderText="{Binding HeaderText}"/>
<TextBlock Text="{Binding HeaderText}"/>
</StackPanel>
</Grid>
</UserControl>
MainPage.xaml.cs
using System.Windows.Controls;
namespace SilverlightApplication1
{
public class Vm
{
public string HeaderText
{ get; set; }
}
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
DataContext = new Vm() { HeaderText = "My Header" };
}
}
}
MyCtrl.xaml (added as new "Silverlight User Control")
<UserControl x:Class="SilverlightApplication1.MyCtrl"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<TextBlock x:Name="txtHeader" />
</Grid>
</UserControl>
MyCtrl.xaml.cs
using System.Windows;
using System.Windows.Controls;
namespace SilverlightApplication1
{
public partial class MyCtrl : UserControl
{
public MyCtrl()
{
InitializeComponent();
}
public static readonly DependencyProperty HeaderTextProperty = DependencyProperty.Register(
"HeaderText", typeof(string), typeof(MyCtrl), null);
public string HeaderText
{
get { return (string)GetValue(HeaderTextProperty); }
set
{
// NEVER CALLED
SetValue(HeaderTextProperty, value);
this.txtHeader.Text = value;
}
}
}
}
The rest of the project is used "as is", i.e. no compiler options were changed and the server part is also left "as is".
Observations:
I see that the getter of Vm.HeaderText is called during a binding
operation but the setter of the DependencyProperty MyCtrl.HeaderText is never called.
The TextBlock in MainPage below the custom control displays the bound value correctly.
There are no compiler warnings.
There are no exceptions thrown.
There are no debug outputs while the application runs.
This feels like something important is silently failing where it shouldn't.
Maybe I can shed some light on your observations and assumptions:
You can update child controls inside a DependencyProperty setter. Call your setter and see for yourself, the update will be performed. You falsely assume the binding engine is obliged to call your setter. Well, it just calls SetValue(HeaderTextProperty, newValue); on your control, no need to call the setter.
Your observation is specified behaviour.
As you figured out, the right way to do it is to use a propertyChanged callback.
The property getter on your viewmodel Vm.HeaderText is called by the binding engine, because your viewmodel is no DependencyObject and HeaderText is no DependencyProperty so there is no SetValue(...) and no GetValue(...)
You can't see any compiler warnings or exceptions, nor is anything silently failing, because there is nothing wrong with your scenario.
Well, seems like you cannot update the child controls inside a DependencyProperty setter (would be interesting to know why and if this is specified behaviour...)
Using this instead works:
public static readonly DependencyProperty HeaderTextProperty = DependencyProperty.Register(
"HeaderText", typeof(string), typeof(MyCtrl), new PropertyMetaData(OnHeaderTextChanged));
public string HeaderText
{
get { return (string)GetValue(HeaderTextProperty); }
set { SetValue(HeaderTextProperty, value); }
}
private static void OnHeaderTextChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var ctrl = d as MyCtrl;
ctrl.txtHeader.Text = (string)e.NewValue;
}