How to preview what a XAML control with bound values looks like - c#

I'm writing an app in XAML, and I'm using binding for getting values to the UI layer. I'd like to see what my control will look like while making changes to the XAML, but because the data values are bound, many areas show up as blank (which, in turn, messes up the relative layout).
Is there any way to give XAML values to use for rendering the control review without replacing the Binding directives?

You can also use design time data to see how your xaml works. You just need to add new class that will be treated as design time view model. Its more elegant way to test xaml at design time.

Maybe you can set TargetNullValue or FallbackValue property in your binding, example:
<TextBlock Text="{Binding NotExsitOrNullPropertyName, TargetNullValue=SomeDefaultValue, FallbackValue=SomeDefaultValue}" ></TextBlock>
Hope it hepls.

Related

Do I need dependency properties for all basic properties on my user control?

I am currently writing my first user control which would consist of a label and a text box in a stack panel like follows:
<Grid>
<StackPanel Orientation="Horizontal" DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Label Content="{Binding Label}" Width="60"></Label>
<TextBox Text="{Binding TextBoxContent}" Width="60"/>
</StackPanel>
</Grid>
This will be most useful to be in a settings page, as it will be reused for several different settings. With each of these settings, I will want to set (at a minimum) the width, height, validation rule and error template properties. As for the text itself, I have already created a dependency property both for the label and the text box (as you can see in my snippet above).
My question is this: Do I need to create a dependency property for all of the properties I just mentioned that I would like to set when I actually use my user control? This seems like redundant work (since they already exist on the text box, basically they would just redirect my user control's property to the text box's property of the same name)? This is even more work if I want to use even more properties on my text box (for example, AcceptsReturn, etc).
The redundant work can be saved if you decide to derive from TextBox rather than UserControl - just think of your control as a "labeled textbox" and all you need to do is derive from TextBox and add the needed dependency properties to accommodate for the label. This of course would not be the case for more complex user controls, but it seems OK in your case.
The downside to this though is that you'll have to take the default control template for TextBox and work with it to add your label, which may be a bit trickier.
Either way, I recommend having a look at the Control Authoring Overview page on MSDN, which is extremely useful when writing your first controls in WPF.

Is it possible to use reflection directly in XAML

In my DB I have a table that contains different items of userControls with the attributes "ClassName", "AssemblyName" and "NameSpace" which are necesarry to init the instances using reflection.
My Idea was To get this collection from the DB, set the collection as the data-context and dynamically load these usercontrols into a tabcontrol. I could use a "tabItem" which would contain it and in runtime in the code behind load it. I guess it would be really handy and fancy if it could be done directly from XAML in a template.
I've been googleling for something similar, but found nothing without using code behind.
I was thinking something like the following
<TabControl.ContentTemplate>
<DataTemplate>
<xxxControl ClassName="{Binding ClassName}" AssemblyName="{Binding AssemblyName}" NameSpace="{Binding NameSpace}" />
</DataTemplate>
</TabControl.ContentTemplate>
I could make such a custom "xxxControl" but it would be a waste of time if something like that already exists. This way The GUI could be completly generated by the parameters in the DB.
You can do a lot of things in XAML using markup extensions, in this case you could create one that instantiates controls from the given information. For that it needs some dependency properties that can be bound, and in ProvideValue it would then get the assembly, construct the full name and instantiate it.
Usage:
<DataTemplate>
<me:Instance Assembly="{Binding AssemblyName}"
NameSpace="{Binding NameSpace}"
Class="{Binding ClassName}"/>
</DataTemplate>
Obviously you still have code-behind, but that is how it should be, imperative code does not belong in XAML at all.
Also i doubt that your data-base should contain information about UI controls...
Ugh. Don't control your UI from the database directly. The closest you should come (assuming you can't make significant architecture changes) IMO would be to load your DB entries into an IObservable in your VM and use a DataTemplateSelector to translate your collection into UI controls.

Understanding DataBinding

I'm new to WPF and the whole data binding thing. I read a couple of posts and I'm quite confused about how to bind my data to a UI element.
I saw a post doing it this way:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Name="myWindow">
<Grid>
<TextBox Text="{Binding Path=Speed, ElementName=myWindow}" />
</Grid>
</Window>
This assumes Speed is a property / member defined in the code-behind file. A few other people named binding using a static resource and reference this one and others named DataContext to be used for binding. Now, because I'm new to WPF's data binding, I'm quite unsure if there exists any best practice method about which data binding to use.
Basically I was wondering why there has to be a several class-property defined as kind of connector to the underlying viewmodel, I though this stuff was more "dynamically".
I'm aiming at only having the XAML file, without the need to add anything into the *.xaml.cs code behind file. For example: I have a class named MainWindowViewModel (which will represent my ViewModel) having a member of the type ObservableCollection<string> and I want to bind a ListBox (in my View) to this collection. The only way I got this working so far was using the the first case, ElementName, where I have to add a property to the view-class as a kind of connector. Just like this:
MainWindow.xaml:
<Window x:Class="Sample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Name="MW" Title="MainWindow" Height="419" Width="463">
<Grid>
<ListBox ItemsSource="{Binding ElementName=MW, Path=ListerResultConnector}" />
</Grid>
</Window>
MainWindow.xaml.cs:
private ObservableCollection<string> mListerResultData = MainWindowViewModel.Instance.RetrievalStringResults;
public ObservableCollection<string> ListerResultConnector
{
get { return mListerResultData; }
}
My question is, if there exists a smarter way to bind data to my UI as using as further "connector" property in the code-behind file.
Your ViewModel should be set as the DataContext to the view. Then you don't need any "further connector" in codebehind. Binding actually refers to DataContext and if you don't set it, it remains as 'this', which corresponds to your codebehind file (which is just a partial to your view).
Also, take a look at: WPF Apps With The Model-View-ViewModel Design Pattern
You should get the WPF and it's binding basics first, but once you understand those, I suggest looking at Caliburn Micro and its convention-based bindings, event handling and other features which make your code much cleaner.
Your {Binding ElementName=MW means you are binding to the Window itself, so your DataContext is the Window, and any properties you implement need to be defined in that Window (in your code behind - your "connectors").
You need to remove the ElementName=MW bit and assign your ViewModel as the DataContext so you can bind to its properties directly. How you do this depends on whether you use "ViewModel First", or "View First"
In View first, you manually assign the DataContext to the View in code when you create the view.
In ViewModel first, you create a DataTemplate in XAML that ties your View to a particular ViewModel. I think ViewModel first is more common. The link that Darjan posted should help you understand the difference.
You should use a separate ViewModel class (WindowViewModel) which represents your data context for your Window (Window.DataContext).
I found that using the MVVM Light toolkit and following some of the videos on the site helped me fill in the gaps. Take time to learn it before getting started and it will start to sink in. IoC containers are also mixed in with MVVM + WPF for directory management & lifetime management of view models and improved design-time experience (blendability).
Toolkits aren't required and sometimes get in your way of learning the pattern. Once you understand it though, you should leverage a toolkit to speedup the development process. Here is a comparison of various MVVM toolkits.
A binding generally has two parts: a source object and a property name
When you specify ElementName in a binding, you are setting the Source object. Other ways to specify the binding's source object include the RelativeSource and Source properties. You can also leave the binding's source object undefined, in which case it will use whatever the DataContext is of the current object. The Source Object can be a UI Element found in WPF's VisualTree, or it can be a class object that is in the control's DataContext
When you specify Path, you are telling the binding what Property to use. You can also leave this property blank to bind to the current object's DataContext
The DataContext is the data object stored behind the control. This is typically a Model or a ViewModel (if using MVVM), although it can also be almost any object, such as a UI Element.
In your example
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Name="myWindow">
<Grid>
<TextBox Text="{Binding Path=Speed, ElementName=myWindow}" />
</Grid>
</Window>
you are telling the binding that it's Source Object is the UI Element in the Visual Tree named myWindow, and the property is called Speed. Since your object named myWindow is of type Window, this binding will only work if your Window class actually has a property called Speed.
There are a lot of answers here suggesting you switch to using the MVVM design pattern, and I agree that you should try and use MVVM if you're working with WPF. It makes coding a lot simpler since you are separating your application logic from your UI. If you're interested, I have a simple MVVM example posted on my blog which explains the basics of that design pattern.
Yeah, Binding is nothing if not confusing.
This example from msdn may be helpful. Notice how a DataContext is declared at the Window "level" - it's a complex/compound object in this case and Window sub-elements' {Binding} declarations are therefore implicitly relative to the "Parent level" DataContext.
The main goodness we get is that when the DataContext is set to a given object all the "sub element" data bindings are automagically keep in synch. We can control this synchronization at any/many levels in the UI Control structure heirarchy by using this pattern.
Collection binding under the hood
The bottom line is your collection must implement IList as a minimum. Many .NET Collection classes are "binding ready."
Here's a quote from the msnd doc on ObservableCollection:
Before implementing your own collection, consider using ObservableCollection or one of the existing collection classes, such as List, Collection, and BindingList, among many others. If you have an advanced scenario and want to implement your own collection, consider using IList, which provides a non-generic collection of objects that can be individually accessed by index. Implementing IList provides the best performance with the data binding engine.
Finally, IBinding list vs IList is needed for 2-way binding.
The simplest way to do it would be:
<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ctrl="clr-namespace:WpfApplication4"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ctrl:MainWindowViewModel x:Key="mym" />
</Window.Resources>
<Grid DataContext="{Binding Source={StaticResource mym}}">
<ListBox ItemsSource="{Binding Path=MyListProp}" />
</Grid>
The example above does the following:
Creates a new object of the ViewModel as resource for you window
Assigns the view model as DataContext for the window (more precisley for the root grid)
Binds the List box to your ViewModel ObservableCollection property MyListProp.
Try to get familiar with the properties of the binding class to fully understand this example by using the msdn library.
Also WPF 4 Unleashed - Adam Nathan is a great resource for a wpf beginner. Chapter 13 - Data Binding should cover everything you might want to know about bindings.

Question about ViewModel Management (DesignTime Vs Run Time)

I have a fairly basic WPF UI whereby user requests cause a new tab to open in my TabControl. The TabControl is bound to an ObservableCollection<ViewModelBase>
I add ViewModel instances to this collection, and the corresponding tab's content is displayed based on templates like this:
<DataTemplate DataType="{x:Type viewModels:UserUploadsViewModel}">
<userControls:UserUploads />
</DataTemplate>
Now let's say that inside of the UserUploads control I'd like to wire up a ViewModel in XAML to help with the designing, like this:
<UserControl x:Class=".....UserUploads"
.....
DataContext="{Binding Source={StaticResource ViewModelLocater},
Path=UserAdministrationViewModel}">
This property will return a ViewModel with live services at runtime, and a ViewModel with mock data at design time.
Question: Will this XAML interfere with what I'm doing in binding a TabItems content to a ViewModel instance, and relying on the dataTemplate above to render the right View? If so, is there a way to get both of these concepts to work together?
There is an easier way to do this. Have a DesignTimeUserAdministrationViewModel and populate it with static data in the constructor and refer that in UserControl as:
<UserControl d:DataContext="{d:DesignInstance designTimeVMs:DesignTimeUserAdministrationViewModel, IsDesignTimeCreatable=True}">
This way you have a design time test data bound to d:DataContext and runtime live data bound to the actual DataContext. More details here.
Yes I think it will interfere with your current setup
The ViewModelLocator is a static class that returns a dummy object at design time, and a static ViewModel at runtime. This means that
The ViewModelLocator, not your ParentViewModel, contains your TabViewModels
You cannot have multiple instances of the same Tab (ViewModel) open at once
You cannot manage Open/Closed tabs unless you reference the UserControl, which is a violation of the MVVM principle where the ViewModel doesn't know of the View
You can't instantiate new copies of the TabViewModel with parameterized constructors. For example, OpenTabs.Add(new CustomerViewModel(CustomerId));
Perhaps an alternative could be a Converter? One that returns a static object if in design time, or the bound object during runtime? I've never tested such a thing but in theory it should work :)
The built in MS stuff is not bad, but another more elegant and structurally sound alternative which I am busy incorporating in my project is:
http://msdn.microsoft.com/en-us/magazine/dn169081.aspx
Basically, you use the MVVM Light toolkit with the SimpleIoc container it comes with and end up with the ability to serve up data for the following three scenarios:
Design time, Run time, and Test time.
Better still, the whole point of MVVM Light is to have your stuff be directly editable in Blend and there is a whole series of videos and blogs and sample apps describing it all. I wish I had found these earlier in my WPF explorations.

WPF Combobox binding: can't change selection

After wasting hours on this, following on the heels of my Last Problem, I'm starting to feel that Framework 4 is a master of subtle evil, or my PC is haunted.
I have three comboboxes and a textbox on a WPF form, and I have an out-of-the-box Subsonic 3 ActiveRecord DAL.
When I load this "edit record" form, the comboboxes fill correctly, they select the correct items, and the textbox has the correct text. I can change the TextBox text and save the record just fine, but the comboboxes CANNOT BE CHANGED. The lists drop down and highlight, but when you click on an item, the item selected stays the same.
Here's my XAML:
<StackPanel Orientation="Horizontal" Margin="10,10,0,0">
<TextBlock Width="80">Asset</TextBlock>
<ComboBox Name="cboAsset" Width="180"
DisplayMemberPath="AssetName"
SelectedValuePath="AssetID"
SelectedValue="{Binding AssetID}" ></ComboBox>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="10,10,0,0">
<TextBlock Width="80">Status</TextBlock>
<ComboBox Name="cboStatus" Width="180"
DisplayMemberPath="JobStatusDesc" SelectedValuePath="JobStatusID"
SelectedValue="{Binding JobStatusID}" ></ComboBox>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="10,10,0,0">
<TextBlock Width="80">Category</TextBlock>
<ComboBox Name="cboCategories" Width="180"
DisplayMemberPath="CategoryName"
SelectedValuePath="JobCategoryID"
SelectedValue="{Binding JobCategoryID}" ></ComboBox>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="10,10,0,0">
<TextBlock Width="80">Reason</TextBlock>
<TextBox Name="txtReason" Width="380" Text="{Binding Reason}"/>
</StackPanel>
Here are the relevant snips of my code (intJobID is passed in):
SvcMgrDAL.Job oJob;
IQueryable<SvcMgrDAL.JobCategory> oCategories = SvcMgrDAL.JobCategory.All().OrderBy(x => x.CategoryName);
IQueryable<SvcMgrDAL.Asset> oAssets = SvcMgrDAL.Asset.All().OrderBy(x => x.AssetName);
IQueryable<SvcMgrDAL.JobStatus> oStatus = SvcMgrDAL.JobStatus.All();
cboCategories.ItemsSource = oCategories;
cboStatus.ItemsSource = oStatus;
cboAsset.ItemsSource = oAssets;
this.JobID = intJobID;
oJob = SvcMgrDAL.Job.SingleOrDefault(x => x.JobID == intJobID);
this.DataContext = oJob;
Things I've tried:
Explicitly setting IsReadOnly="false" and IsSynchronizedWithCurrentItem="True"
Changing the combobox ItemSources from IQueryables to Lists.
Building my own Job object (plain vanilla entity class using INotifyPropertyChanged).
Every binding mode for the comboboxes.
ItemsSource="{Binding}"
The Subsonic DAL doesn't implement INotifyPropertyChanged, but I don't see as it'd need to for simple binding like this. I just want to be able to pick something from the dropdown and save it.
Comparing it with my last problem (link at the top of this message), I seem to have something really wierd with data sources going on. Maybe it's a Subsonic thing?
EDIT: For some reason the set accessor is hit only on the AssetID property and only the first time. WPF is now heading for WTF :)
EDIT 2: You gotta be kidding me- I've removed the binding (ie it only has a displaymemberpath, a valuememberpath and an itemssouce) and it's STILL doing it! It accepts your first selection, and then won't change.
WPF Combo Boxes will not change the selected item if the currently selected item and the item that was just selected are considered equal by the object.Equals() method called on the newly selected object (i.e newlyslected.Equals(previoslySelected) ).
Overriding the Equals method on the class your binding the combobox items, should resolve the issue your are seeing.
I've narrowed it down to the Subsonic objects used as ComboBoxItems.
If you create a new class that uses exactly the same code as the relevant parts of the Subsonic one, it works.
If you use POCOs/datatables for the combos and Subsonic for the record being edited, it works.
But if you use Subsonic for both, it doesn't.
I had hoped to extend the subsonic objects and not have to code a full-blown BLL tier. Looks like I'm faced with doing that or throwing out Subsonic for the DAL. I might post a more specific question for the Subsonic folks.
Many thanks to all who contributed.
Old topic but I had the same problem and difficulty finding solution. This might help someone else.
Clue is above in WPF not detecting a different item has been seleted by user. (Symptom - event ComboBox_SelectionChanged only fires on first selection)
My scenario - lookup combo populated from IList built from a DISTINCT query. In this case the result of using NHibernate ICriteria.SetResultTransformer which only returns SOME fields, importantly NOT including the unique entity ID.
Solution - loop thru' IList after retrieval and give each entity a unique ID. WPF sees them as individuals and behaves appropriately.
Its only a value lookup - its the value content I was after.
The 'temporary' entities are never persisted. In this case it was a better approach than messing with overriding the object's Equals method for the sake of a simple GUI issue. An alternative would be to just copy or tranform the list into a format where WPF uses the value field to determine 'difference'...
Sounds like the field is somehow readonly, or that your change isn't being persisted. After the binding sets the new value, it will re-read the property to ensure that it was actually changed. If your property returns the old value, then it'll be re-selected in the combo box, giving the appearance that the value never changed.
I don't know that DAL, but can you step through the property setter code? You might also have an issue with type conversion.
EDIT reading your comment about the red rectangle -- it sounds as though your property (or something to do with the binding) is raising an exception. Unless, of course, you're using data validation in your UI. You might turn 'Break on all exceptions' in the debugger's settings, assuming you're using Visual Studio.
EDIT 2 You should check the VS Output pane for any error messages related to binding. You can also read this blog post which gives more info on debugging bindings.
It's hard to tell from a small sample of your code but try commenting out the line:
//this.DataContext = oJob;
and see if this helps.
Setting the DataContext and ItemsSource might be causing a conflict.
Did you write any global style for your combo box which may have a bug or something missing? Or are you using pure default styles for your combobox? Try removing any default styles applied.
Are you wiring up any events? If your code hooks up for event like PreviewMouseLeftButtonUp and marks event as handled then probably combobox may ignore and wont select anything.

Categories

Resources