I'm missing the boat on something here, kids. This keeps rearing its head and I don't know what's going on with it, so I hope my homeys here can help.
When working in Silverlight, when I create bindings in my c# code, they never hold up when the application is running. The declarative bindings from my xaml seem ok, but I'm doing something wrong when I create my bindings in C#. I'm hoping that there is something blindingly obvious I'm missing. Here's a typical binding that gets crushed:
TextBlock tb = new TextBlock();
Binding b = new Binding("FontSize");
b.Source = this;
tb.SetBinding(TextBlock.FontSizeProperty, b);
I've just tried the exact code you just posted and it worked fine, with some changes. I believe the problem is the element you are using for the SetBinding call is not the textblock you want to bind. It should be:
TextBlock tb = new TextBlock();
Binding b = new Binding("FontSize");
b.Source = this;
tb.SetBinding(TextBlock.FontSizeProperty, b);
Make sure you also have a FontSize public property of type double on "this". If "this" is a user control, I would recommend renaming the property so you don't hide the inherited member.
It looks like as of Silverlight 3.1, at least, this is no longer an issue. I can't reproduce it, at any rate.
Related
I'm trying to create a login screen but I want to do everything through code.
So generating the full UI through C#.
But I'm working with MVVM model and I have data binding on my username but this doesn't work on the standard PasswordBox so I found a namespace online which makes a workarround, it's called PasswordBoxAssistant from FunctionalFun.UI.
In the xaml I can create a passwordbox with the assistant but I'm making my UI through code and I'm not able to find how to use the PasswordBoxAssistant like that.
So I have this:
And want the same thing but in my C#
But like you see in my code, I don't have access to it.
No idea if the xaml will only be to access it with everything is compile or why I can't use it in my C#.
Anybody that can help me implement this or point me to a direction?
It seems PasswordBoxAssistant is an attached property similar to PassWordHelper here:
https://gist.github.com/alamsal/fcefce4fb2d2d70fb2d91ee12741a35f
You attach such properties as described here:
https://learn.microsoft.com/en-us/previous-versions/dotnet/netframework-4.0/ms749011(v=vs.100)#attached-properties-in-code
Hence something like
PasswordBoxAssistant.SetBindPassword(yourPasswordBox, true);
Would add that to a variable yourPasswordBox.
You then need to create a binding on the BoundPassword dependency property of course.
https://learn.microsoft.com/en-us/dotnet/desktop/wpf/data/how-to-create-a-binding-in-code?view=netframeworkdesktop-4.8
The property you are binding as target is the PasswordBoxAssistant dependency property.
Bindings are a bit fiddly in code. I have used the approach rarely.
A rough example:
Binding myBinding = new Binding();
// myBinding.Source = ViewModel; Datacontext is default, you probably don't need source.
myBinding.Path = new PropertyPath("SomeStringPropertyInDatacontext");
myBinding.Mode = BindingMode.TwoWay;
myBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
yourPasswordBox.SetBinding(PasswordBoxAssistant.BoundPasswordProperty, myBinding);
I have created a smaller test project from a far complex actual project but the idea is the same. Both have the same problem.
I have two classes, A and B. A is a type of ContentControl and B is a type of FrameworkElement. A has a dependency property Bee (type of B). B has a dependency property Text (type of string). A's default value is null and B's default values is "B There!".
I'm using styling in my test window (Window.Resources) to set B's Text property to something else than the default value.
<Window.Resources>
<Style TargetType="local:B">
<Setter Property="Text" Value="YO!!!"/>
</Style>
</Window.Resources>
When I set A.Content to a new instance of B, everything works like a charm most likely because the system handles everything. I.e. when I change style setter's value in Visual Studio's designer, it changes the corresponding property value (B.Text). Data binding works fine, also.
<local:A.Content>
<local:B/>
</local:A.Content>
What I actually need is below...
For reasons I cannot control I cannot use A.Content for this so I create a new B instance and set it to A.Bee property. In this case implicit styling and data context inheritance does not work. I.e. when I change style setter's value, nothing happens and data binding does not work either.
<local:A.Bee>
<local:B/>
</local:A.Bee>
In A.Bee property value changed callback I use AddLogicalChild, AddVisualChild and data binding to put the B instance into the trees and make data binding work. I.e. when A.Bee is set, the below happens (simplified)...
private static void BeeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
A instanceOfA = d as A;
B newValue = e.NewValue as B;
Binding b = new Binding("DataContext");
b.Source = instanceOfA;
BindingOperations.SetBinding(newValue, B.DataContextProperty, b);
instanceOfA.AddLogicalChild(newValue);
instanceOfA.AddVisualChild(newValue);
}
This fixes the data binding problem. Not sure if this is a correct way, but it works. Let me know if there's a better way. However, styling still does not work in Visual Studio's designer.
How can I bind to styling values so that property values change when I change style setter's values in Visual Studio's designer?
newValue has no style in its resources until AddLogicalChild is used so I think I'm on the right tracks but not quite there, yet...
If necessary, I can add a link to my project if someone wants to test/modify it.
Here's a link to the test solution (Visual Studio 2013): FEStyleTesting
In a nutshell, I want setting the A.Bee property with an instance of B class to work just like setting the A.Content property with an instance of B class. I.e. data context and styles are inherited to the instance of B class when using Visual Studio Designer.
In the image, I'm debugging the designer and as you can see, the style setters can be found from resources after AddLogicalChild is called but for some reason the style isn't applied in designer... And there's a third setter for InstantietedElementViewNode property when in designer. I.e. it's not there in run-time. Maybe it's something the designer adds for every control... The first two setters are the ones defined in XAML (forgot to expand them for the picture).
Just to clarify, in the test application the idea is to use the message boxes for testing. I.e. I don't need the visual appearance to change (which it does when using the Content property). Just get the callbacks invoked when style setter values are changed in XAML.
Here are steps to test this problem:
Open the solution.
Make sure that no source tab pages are open.
Rebuild the solution just in case.
Open MainWindow.xaml (double-click it).
Click "Ok" button if message boxes appear.
Make sure that the first assignment under "These don't work" is uncommented and the other three are commented out. (Can't get source code in this list for some reason...)
Now change the value of the style setter for Text property to e.g. "YO2!!!".
A "TextChanged" message box should appear after editing the value (but it doesn't).
B is derived from ContentControl (and not from FrameworkElement) on purpose so that I could verify data binding and style inheritance when using the A.Content property. ContentControl is derived from FrameworkElement so the outcome should be the same. FrameworkElement is used in my larger project.
While debugging the designer, I changed "YO!!!" to "YO2!!!" and then changed B.Color explicitly in XAML. Then in ColorChanged callback I took a look at B instance's resources and noticed that the value had changed accordingly. So styling values are updated when I change them in XAML but they don't change the property value for some reason (Text is still "YO!!!")... Hence, no callbacks invoked.
I wonder what might cause this...
I may have found a possible solution. I noticed that even though I called AddLogicalChild, A.LogicalChildren did not contain the B object. I then went through overridable methods and ran into overridable LogicalChildren property.
Here's my version:
protected override IEnumerator LogicalChildren
{
get
{
List<object> list = new List<object>();
while (base.LogicalChildren.MoveNext() == true)
{
try
{
list.Add(base.LogicalChildren.Current);
}
catch
{
// If Current fails, break.
break;
}
}
list.Add(Bee);
return list.GetEnumerator();
}
}
Not sure if this is the "ultimate" solution but now my property changed callbacks are invoked every time I change style setter values. Well, live and learn... Better test this some more.
So the answer to the problem is to override LogicalChildren property to include the nested object. This will also remove the need for BindingOperations to bind to DataContext. AddLogicalChild is still required. Not sure about AddVisualChild but better safe than sorry...
I'm trying to change the default style of the contextmenu to 2013/2015 in my rehosted vs13 application.
The problem occurs in only one designer, everywhere else its the correct one. I've tried to override both the XAML code and the code behind, checked if something else was changing the style, but without anykind of result.
Is there even a way to change the default style? Am I overseeing something?
Okay, after some heavy research/try and error if finally found out what was wrong: I couldnt access the control I wanted to change the ordinary way, so I had to think outside of the box (and ask a collegue for help).
This is the code that works for me, its not pretty, but it deletes the 'standard'-style set by WPF.
var dv = wd.Context.Services.GetService<DesignerView>();
dv.MenuItemStyle = null;
dv.MenuSeparatorStyle = null;
dv.Resources[typeof(ContextMenu)] = new Style(typeof(ContextMenu));
Quick thanks to Glen Thomas for trying to help.
I have a C# WPF application with a bunch of labels.
When I run my program it does some checks and wether it the check was positive or not it sets it's corrisponding label to green og red.
These changes is done in my .cs file like:
lblCheck14.Foreground = new SolidColorBrush(Colors.Green);
I would like to add a "Reset" button, that reset the application to it's initial start.
How can I easiest implement this?
One way - but I really hope there is a smarter way, is to set them all like:
lblCheck14.Foreground = new SolidColorBrush(Colors.Black);
lblCheck21.Foreground = new SolidColorBrush(Colors.Black);
lblCheck42.Foreground = new SolidColorBrush(Colors.Black);
Etc..
But isn't there a function which I can call that strips away any changes the .cs file have done to the controls in the XAML file? Like make the XAML back to stock?
Sorry for my back explanation. Hope you understand me :)
Best regards
Implement styles. You can have a default style to roll back to when you hit reset.
Take a look at this tutorial if you're unfamiliar with them: http://wpftutorial.net/Styles.html
Do not manipulate UIElements' properties in code. WPF is not winforms. As Yatrix's answer said, implement styles, or even datatemplates and triggers to manipulate different properties of different UIElements acording to some logic (defined in ViewModel or somewhere else). I suggest you to take a look at WPFTutorial.net
I'm using XamlReader successfully to load a xaml file and create a FrameworkElement to work with.
The xaml I'm loading has binding expressions in it such as:
<TextBlock Text="{Binding DataContextTextProperty}" />
If I place the FrameworkElement I get back from XamlReader.Load() into a WPF window, the binding all works fine.
However, in this case I'm using Laurent Bugnion's excellent article on creating PNGs from WPF/XAML. Since the result of XamlReader.Load() is written directly to a PNG via a VisualBrush, it seems the necessary mechanics of WPF to invoke binding expressions are bypassed.
This leads me to believe that the actual bindings aren't really being invoked just by calling XamlReader.Load(), or that they're not working because of something I don't know about to do with there not being a visual tree until you add the FrameworkElement to an existing visual tree or something.
Is there something I can do to ensure these bindings are invoked?
Many thanks in advance.
I FIXED IT!!
Ahem, allow me to explain...
I have no idea how I got to it now, but I found a helpful-sounding article on MSDN regarding Initialization for Objects Not in an Object Tree.
In it I found the following code example:
Button b = new Button();
b.BeginInit();
b.Background = Brushes.Blue;
b.Width = b.Height = 200;
b.EndInit();
b.Measure(paperSize);
b.Arrange(new Rect(paperSize));
b.UpdateLayout();
I looked at the (again, excellent) example from Laurent that I mentioned in the question above, and customised the use of XamlReader as follows:
var element = (FrameworkElement)XamlReader.Load(xamlInput);
element.BeginInit();
element.DataContext = dataContext;
...
element.Measure(renderingSize);
element.Arrange(renderingRectangle);
element.EndInit();
element.UpdateLayout();
I added the BeginInit(), EndInit() and UpdateLayout() (though by process of elimination I believe UpdateLayout() is the key) and now the binding expressions in my dynamically-loaded xaml are working correctly. Hurrah!