I'd like to be able to use arbitrary C# expressions in XAML. Usually this would be to compute a property for a UI element based on two bound values.
For example calculating the width of a UI element based on two other properties.
This is a contrived example of what I'd like the XAML to look like:
<TextBox
x:Name="textBox1"
/>
<TextBox
x:Name="textBox2"
/>
<Rectangle
Height={Double.Parse(textBox1.Text) + Double.Parse(textBox2.Text)}
/>
Of course there is no built-in way of doing this in XAML.
I know that I could use a MultiBinding combined with a custom converter and this is usually the way I do this kind of thing. However it seems to me that it would be so much simpler to just include some C# code in the XAML and I was wondering if anyone out there had already solved this problem with a XAML extension or something else.
You embed C# code into XAML like this:
<x:Code>
<![CDATA[
void ButtonOnClick(object sender, RoutedEventArgs args)
{
Button btn = sender as Button;
MessageBox.Show("The button labeled '" +
btn.Content +
"' has been clicked.","Information Message");
}
]]>
</x:Code>
But this approach is not recommended at all because it mixes the pure presentation layer with business logic.
I've seen custom Xaml converters that take IronPython code and Invoke the DLR. It's not quite C#, but its certainly is less ugly than the approach of using [CDATA] tags.
http://pybinding.codeplex.com/
This is the link to an open source project on the matter.
Wrap your expression into a public property and bind to that property.
In C# codebehind:
public double Heigth
{
get { return Double.Parse(textBox1.Text) + Double.Parse(textBox2.Text); }
}
In XAML:
<Rectangle Height={Binding Heigth} />
Please mind that with the code like
Height={Double.Parse(textBox1.Text) + Double.Parse(textBox2.Text)}
it's particularly hard (although not completely impossible, keeping Linq Expressions in mind) to get the value reevaluated as soon as some of the operands change. The automatic update of the target value when the source changes is one of the major advantages of WPF bindings.
I have an answer to my question now. It isn't the answer I was originally looking for, and it is a bit long winded but it does work.
I was reading this post by Josh Smith. He recommends not using value converters but pushing the calculations down into the view-model and exposing it as a property:
http://groups.google.com/group/wpf-disciples/browse_thread/thread/3fe270cd107f184f?pli=1
In my case the text for both 'textBox1' and 'textBox2' should be bound into the view-model, so when they change in the view-model I know its time to do the calculation and update the dependent property. The dependent property then fires its property changed event and the UI updates from that.
If you have a case where you want to make the expression depend on read-only control properties, that you can't easily bind to the view-model, you can follow the advice presented here:
Pushing read-only GUI properties back into ViewModel
I still would like to have the ability to embed (non-business logic) expressions in the XAML. But seeing as this is not built-in any way of doing it is likely to be a bit of a hack. Going through the view-model seems to be the correct way of doing this, but maybe one-day I'll experiment with writing a markup extension that allows expression in XAML.
Related
<Grid Name="mainSceneGrid" Grid.Row="1" Background="#FF075035">
<Grid Name="navigationGrid">
......
</Grid>
</Grid>
Normally from the code behind we would directly call navigationGrid.xxx which is very simple and effective. However when we start to get alot of dependent and nested grids for example it would be awesome to instead be able to call a property like this:
mainSceneGrid.navigationGrid.xxx
So we get some form of structured code and easier intellisense to work with, is this possible with xaml?
You misunderstand what the names of UI elements are.
For XAML, firstly, it is registering a name in the visual tree of elements using the FrameworkElement.RegisterName (String, Object) method and then searching in this tree using the FrameworkElement.FindName (String) method.
This is mainly used for bindings of type ElementName.
These names must be unique within the scope of the names.
Secondly, the x: Name Directive creates, in addition to the name in the visual tree, a field in the "* .g.i.cs" file.
This file is the XAML reflection generated by Studio Designer.
You can view it if you place the cursor on the call to the InitializeComponent () method and press F12.
It automatically changes when you change the XAML code.
And when you reference the name of an element in Code Behind, you are not actually referring to the name in XAML, but to a field in that file.
And if you know even a little about Sharpe, then you understand that you cannot create fields with names like name1.name2.
As for your problem, its origins are that you are not working with WPF in a way that is typical for WPF.
WPF is designed around the concept of UI elements getting values for their properties on their own through bindings.
Therefore, using WPF element names other than ElementName bindings is a sign of incorrect implementation.
Such incorrect implementation methods are fraught with the occurrence of specific tasks, code bloat, and a high probability of bugs and errors.
I advise you, especially at the initial stage of training, in general, do not even open the "* .xaml.cs" files.
There should be nothing in the Code Behind other than calling the InitializeComponent () method.
When you learn the basics of WPF (layout, bindings, data context, styles, templates, triggers, converters), then you will be able to consciously decide on the use of Code Behind.
But in practice, there are almost no such tasks where it is really needed.
I have a screen with a TextBox in which the user can type a 2-character state code. Below the TextBox is a ListBox containing all 50 state codes. The TextBox is bound to property in the VM, and the SelectedItem is bound to a property in the VM. That all works fine.
The way I want the UI to work is when the user selects a state from the ListBox, the TextBox is automatically filled in, and this works fine.
Where it gets messy is when the user types in the state in the TextBox. When I get the first character, what I want to do is reposition the list box at the first matching state code for that letter, so for instance, if the ListBox is sitting at "AK" (Alaska) and the user is going to type "ID" for Idaho, when I get the "I" I want to position the ListBox so you can see the first "I" state, which is "IA" (Iowa).
If I use code behind and point SelectionChanged=BringSelectionIntoView with this method coded as follows, it works great:
private void BringSelectionIntoView(object sender, SelectionChangedEventArgs e)
{
ListBox lb = (ListBox)sender;
lb.ScrollIntoView(lb.SelectedItem);
}
All I have to do is scan the list of state codes until the first letter matches, then update the Index property to which SelectedIndex is bound, and poof, the BringSelectionIntoView() method gets invoked and I have exactly the UI behavior I want.
Trying to do this in a purest MVVM methodology, however, has proved quite frustrating. I'm not using MVVMLight or ExpressionBlend--I want a simple way to do this in MVVM. I understand the purest's mindset of not putting any UI code in the view, but the framework is insanely cumbersome to enact this kind of behavior. There's a point of diminishing returns when you have to create such obtuse plumbing to force yourself to adhere to a pattern when it's far more practical to put in the method with 2 lines of code that works perfectly.
So my question is this: am I doing something wrong and is there a simple way to make this work without violating MVVM? It's disappointing if the solution requires additional SDKs or someone's framework. That would suggest that MVVM doesn't have particularly good legs to stand on in a generic OOP sense.
Does someone see an error in what I'm trying to do, or do you see a simplistic solution here? Thanks!
MVVM is not about not having any code behind.
What you're talking about here is VIEW behavior. Which fits perfectly in the code behind, as long as you're not messing with the DATA in the event handlers.
You're using a VIEW event handler to manipulate a VIEW aspect.
That doesn't break MVVM.
Keep it that way. Keep it Simple.
You should still have a ViewModel and a Model to hold the DATA that the UI shows.
This is a perfect use case for an attached behavior. You can write this behavior once and use it for all listboxes without ever having to write any additional code. If you would like me to elaborate, ask and I'll post more information.
Well, i must admit, still sometimes XAML seems a bit mysterious to me. The thing is, i always liked to debug through the C# code (setting lots of breakpoints in them) to get the idea of "what is happening" and "how is it happening". But with declarative XAML syntax that's not an option. I think you'll agree that to work with XAML, or to be precise, to work with/understand some existing XAML code you got to "already know" how things work with XAML declaration. There is just no way you can know/learn things investigating the execution of your application code. So i'm more than interested to take a look through XAML inside-out, as detailed as possible. I'm NOT talking about "learning" XAML, I know the basic stuff. May be i can provide some examples to clarify the sort of things i'm looking for -
Compared to C# code how an object gets instantiated when we use them in XMAL? Are they stored in managed heap? Same way as C# code-instantiated objects?
How the properties get set while using Mark-Up Extension syntax for Data/Command Binding?
When any property of an INotifyPropertyChanged type gets updated, how the Binding instatnce inside the XAML syntax updates the itself? How exactly it gets notified it at the first place, & by whom?
A viewmodel can be set as the DataContext of a view at runtime by defining Typed DataTemplate, like -
<DataTemplate DataType="{x:Type viewmodels:AccountsViewModel}">
<views:Accounts/>
</DataTemplate>
How does it happen actually? What are the rules for setting DataContext other than searching for the DataContext property upward the logical tree?
How the whole template things (DataTemplate, ControlTemplate & ItemsPanelTemplate) are treated/resolved at run time.
etc. etc. etc.
So if you are good/experienced/expert in XAML what would you suggest (links, articles, blogposts, books whatever) as reference that helps getting clear & deeper understanding about how XAML works "under-the-hood"? Thanks in advance.
Most can be explained by don't thinking of XAML as a real programming language, more like a declarative language. Everything you do in xaml, can be made in C# aswell, and in fact this is whats happening.
Compared to C# code how an object gets instantiated when we use them
in XMAL? Are they stored in managed heap? Same way as C#
code-instantiated objects?
Yes because they are just c# objects. Most resources are stored in a hibernated state, i rememberd the word inflated somewhere. Converter or other "direct" c# objects are created when they are needed. Important here is that these resources are usually shared, so they will get created only once.
How the properties get set while using Mark-Up Extension syntax for Data/Command Binding?
This again depends on where you use the markup extension. In a Style? In a Template? In a instanced user control like a window? Usually they are evaluated when you actually need them. It wouldn't make sense to evaluate them, when the inflated style is stored in the actual resource dictionary. They get evaluated when you actually use the style on an object.
When any property of an INotifyPropertyChanged type gets updated, how
the Binding instatnce inside the XAML syntax updates the itself? How
exactly it gets notified it at the first place, & by whom?
By the binding engine. WPF checks if your DataContext inherits the INotifyPropertyChanged interface, attaches to the event provided by the interface and listens to any changes. If such an event is raised, the binding engine will just call the getter again.
How does it happen actually? What are the rules for setting DataContext
other than searching for the DataContext property upward
the logical tree?
In short: None other. Datacontext is simply an inherited attached property. If you don't re set it on a child control, it will take the value the parent has until it reached the root. The only exception to this are ContentControls and ContentPresenter they will not inherit the DataContext but will change them depending on the content. So these controls always have by default the Content as their DataContext.
How the whole template things (DataTemplate, ControlTemplate & ItemsPanelTemplate) are treated/resolved at run time.
Simply spoken: Everytime WPF finds a non ui object, it tries to find a DataTemplate for the given type. In an ItemsControl for example: You can bind a list of MyClass; unless you provide an explicit DataTemplate or DataTemplateSelector it will search the resource tree upwards for an implicit style. Again remember that this already does not happen in XAML, but on the C# objects that was generated out of the xaml.
And is it by any means possible (at present or near future) to debug
through XAML code?
How do you think you can debug something that is not executed, but evaluated on compile time?
Please don't take this as 100% correct. Over the Years this is what i gathered of informations about XAML and the usage. If you have any corrections or find something that is clearly wrong. Please tell me, we are all here to learn and i always learn new things about the stuff i use :)
I have not been able to find a clean solution to the following problem even though there are a few related questions already on SO.
If I have a data template that is being used multiple times, for example, a TreeViewItem.HeaderTemplate, how can I change something the template for only some of the TreeViewItems.
For example, let's say my TVI HeaderTemplate has a textblock and depending on the string, I want to make the fontweight bold.
I want to do something like this:
((TextBlock)myTreeView.Items.ElementAt(0).FindName("myTextBlock")).FontWeight = FontWeights.Bold;
Does anyone have a solution for this? --> Thanks Evan
Edit: Is there a way to write a generic function to get a control based on it's name even if it's in a data template?
LayoutRoot.FindName("myTextBlock"); would work if myTextBlock was not in a datatemplate. How can I write a findElementInDataTemplate(string elementName, string parentName) function?
The reason Evan's answer is not what I'm looking for is because I am developing a control. I want the application developer who uses my control to be able to change any element in the control. If I use Evan's solution, that would require the application developer to have access to all the templates in the control. Possible, but not ideal. Thanks!
One way I have accomplished this is to store all the needed items in a class-level collection variable by using the Loaded event of the control. Take this DataTemplate for example.
<DataTemplate>
...
<TextBlock Loaded="TemplateTextBlock_Loaded" />
</DataTemplate>
Then you use the Loaded event to load up some sort of collection for later use.
private List<TextBlock> templateTextBlocks = new List<TextBlock>();
private void TemplateTextBlock_Loaded(object sender, RoutedEventArgs e)
{
TextBlock tb = sender as TextBlock;
if (!this.templateTextBlocks.Contains(tb)) this.templateTextBlocks.Add(tb);
}
Of course, if you're going to be loading and unloading the control, this may not work well for you.
If you're using data binding, have you tried using a binding converter? In this case you would do something like...
FontWeight={Binding Path=TextProperty, Converter={StaticResource BoldConverter}}
And the converter would be along the lines of...
string myTestString = (string)value;
if (myTestString.Contains("Bob"))
return FontWeights.Bold;
return FontWeights.Normal;
Which makes it less painful to try and root through the elements to locate a particular one.
My first reaction to such a requirement would be: are you really sure you want to be doing that? I would normally urge developers to look at the existing control patterns being used. In this case what you seem a Templated control would seem warranted.
Of course this doesn't provide the flexibility you are after. What you seem to be after is the "holy grail" of customisable controls, the desire to tweak any minor detail about the control without having to duplicate the entire template of the control. OF course this isn't really possible declaratively, if it were I'd dread the syntax and semantic rules that would govern it.
Having said that there are always exceptions. So I'll present a possible option despite feeling that you shouldn't be doing this.
This old answer provides a Descendents extension method allow you to enumerate controls across the object tree. Given an instance of a TreeViewItem you should be able to find the TextBlock you are after with:-
TextBlock tb = treeViewItem.Descendents()
.OfType<TextBlock>()
.Where(t => t.Name == "myTextBlock")
.FirstOrDefault();
what version of silverlight is this?
And what year of " Aug 10 at 18:55" is this post from?
in the current version of SL4 it does not seem to be there..
can also try this
TextBlock txtBlk = grd.FindName("txtBlkName") as TextBlock;
where grd = your root element (Parent of the element you are looking for)
Is there a way to get WPF to automatically apply a Converter to all bindings of a specific type?
I've seen this question, but it covers a different case (localisation) and thus has no satisfying answers.
My problem: I've got model classes containing Commands, which I would like to bind to WPF Commands. Since the model classes are toolkit-independent, I cannot implement WPF's ICommand there. Instead I have a CommandConverter which wraps CommandModels into WPF ICommands:
<Button Command="{Binding MyCommand, Converter={StaticResource CommandConverter}}" />
This works quite well, except that it is easy to forget about the Converter= and WPF doesn't give any indication that the binding failed.
My question is now: Is there a possibility to force WPF to always a apply a converter to specific types of bindings? Or, alternatively, how can I get WPF to give me proper errors when a Command binding fails?
I don't think you can without either sub-classing Button (you probably don't want to do this), or defining your own attached property and using a TypeConverter attribute on it.
If you want to go with using a default converter via the TypeConverter attribute on a new attached property, you can look at Rob Relyea's informative post here, or MSDN here.
While I've never done it, would it be possible to define a custom Markup Extension? That should cause the value to be sent to your class that implements the Markup Extension, and then from there you can return an ICommand that the Command property is expecting.
As I said, I've never created one my self, but a Google Search seems to bring up a few articles on how to do it.
Check the debug output window. Normally you get to see the binding errors there.