WPF editable textblock itemscontrol MVVM - wpf

I have an itemscontrol with repeating stackpanels with child controls. Each stackpanel contains a textblock I wish to be editable. The project has a MVVM framework implemented what makes this a difficult one. I think the best way is to make a button inside each stackpanel that is connected to a BooleanToVisibilityConverter. This converter is connected to a textblock and inverted to a textbox. So it shows one of the two. The problem is I am having trouble realizing this solution.
If i bind the visibility to the back-end then this will result in showing all the textblocks or non. The solution i have now is as following:
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<CheckBox x:Name="DisplayBox" IsChecked="False"/>
<TextBlock Visibility="{Binding ElementName=DisplayBox,
Path=IsChecked,
Converter={StaticResource BoolToVis}}">
<Run Text="{Binding Title}"/>
</TextBlock>
</StackPanel>
So my question is:
Is there a simple way to implement an editable textblock with only XAML binded to each control? Or do I need to implement a way that connects it to the back-end.

this will result in showing all the textblocks
Using the name of a control to bind to it is a strategy I use quite often, but this time it has let you down for you are in a repeating template. For using that binding process in a template makes the selection becomes global and not local.
So one strategy is to use a RelativeSource binding and point to the local parent (the checkbox) such as:
<CheckBox IsChecked="False">
<TextBlock Visibility="{Binding IsChecked,
Converter={StaticResource BoolToVis},
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type CheckBox}
}
}">
<Run Text="{Binding Title}" />
</TextBlock>
</CheckBox>
As an aside and don't read this the wrong way,
project has a MVVM framework implemented what makes this a difficult one.
MVVM is simply a way to separate code concerns (operations, classes and GUI) and frankly shouldn't necessarily come into play when dealing with Xaml bindings.
Whether the data resides on a VM or the page is immaterial for what is required is to set the page's datacontext or the control's datacontext with a valid class instance to be reflected by the binding system. Nothing more nothing less.
For new programmers there are a lot of concepts such as MVVM and binding and that learning curve is significant. My advice is that the buzzword used to be Three tiered systems..now its MVVM or MVC but in the end they all do much of the same, just separation of those programming concerns.

Related

Josh Smith's legendary article: I need a bit more on the DataBinding that takes place

It’s about the MSDN article of Josh Smith on MVVM and the sample application. I know there are lots of question on SO about this topic, and I’ve explored them all. Most of them are focused on MVVM, but my issue is, I think, more XAML related than MVVM.
The sample application contains the following XAML for the Workspaces area -
<Border Grid.Column="2" Style="{StaticResource MainBorderStyle}">
<ContentControl Content="{Binding Path=Workspaces}" ContentTemplate="{StaticResource ResourceKey=WorkspacesTemplate}"/>
</Border>
and the related resources are -
//Explains how to render the 'Workspace' content area in the main window
<DataTemplate x:Key="WorkspacesTemplate">
<TabControl Margin="4" ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True"
ItemTemplate="{StaticResource ResourceKey=ClosableTabItemTemplate}"/>
</DataTemplate>
//Explains how to render a tab item with a close button
<DataTemplate x:Key="ClosableTabItemTemplate">
<DockPanel Width="120">
<Button Command="{Binding Path=CloseCommand}" Content="X" Cursor="Hand"
DockPanel.Dock="Right" Focusable="False" FontFamily="Courier"
FontSize="9" FontWeight="Bold" Margin="0,1,0,0" Padding="0"
VerticalContentAlignment="Bottom" Width="16" Height="16"/>
<ContentPresenter Content="{Binding Path=DisplayName}" VerticalAlignment="Center"/>
</DockPanel>
</DataTemplate>
What I still don't understand -
The syntax ItemsSource="{Binding}" should bind the ItemsSource directly to the TabControl’s DataContext, rather than to any of the DataContext’s properties. But where exactly is the TabControl’s DataContext being set?
How exactly is Content="{Binding Path=Workspaces}" creating a binding between ItemsSource of the TabControl and the Workspaces (the ObservableCollection of WorkspaceViewModel)?
The article says By relying on data binding, the Content property of a TabItem receives a ViewModelBase-derived object to display. How ?!? Ok, through data binding. But that is just too much to abstract away, for me.
In general I’m missing the way binding is flowing/working through these two resources behind the scene to load the Views in the TabItems. To me it's like, what is causing what to be bound to what.
This legendary article and the sample application is something extremely useful for WPF/MVVM beginners. But it’s not much elaborative. I myself have learned using MVVM with this one. I think there is and will be some others like me. So, can anyone explain the binding sequences a little bit more elaborately please?
Relevant Note :
May be it'll give you a hint of what I already know in this context, and help you in answering. I'm a beginner level WPF application developer. With my not so good knowledge on XAML -
I’m aware of the magic through typed-DataTemplate of displaying the View when the ViewModel type occurs, and then setting the ViewModel as the DataContext of that View
My understanding is, Content tells what to display on a ContentControl and ContentTemplate tells how to display that Content.
I have a little more than basic data binding concept, and I've worked in some WPF/MVVM projects.
The syntax ItemsSource="{Binding}" should bind the ItemsSource
directly to the TabControl’s DataContext, rather than to any of the
DataContext’s properties. But where exactly is the TabControl’s
DataContext being set?
By virtue of being a data template, the TabControl will have its DataContext set (by WPF) to the data item it is templating. In fact, the root-level item in the data template will have its DataContext set by WPF. In this case, it's a TabControl.
Since the data template is assigned to the ContentControl's ContentTemplate property, it will automatically receive the ContentControl's Content as its DataContext.
How exactly is Content="{Binding Path=Workspaces}" creating a binding
between ItemsSource of the TabControl and the Workspaces (the
ObservableCollection of WorkspaceViewModel)?
I think my previous answer addresses this, but let me re-state it in a form that directly answers this question. The binding on the ContentControl ensures that the DataContext for the DataTemplate is set to the workspace collection. Thus, the TabControl can bind to the workspace collection by specifying a Binding without a Path.
The article says By relying on data binding, the Content property of a
TabItem receives a ViewModelBase-derived object to display. How ?!?
Ok, through data binding. But that is just too much to abstract away,
for me.
Again, this comes down to WPF automatically assigning the correct object as the data context of the generated item (a TabItem in this case). When an ItemsControl (such as TabControl) is bound to a collection, it generates a container (a TabItem in this case) for each item in the bound collection. The container automatically receives the data item (a workspace view model in this case) as its data context.
"But where exactly is the TabControl’s DataContext being set?" Workspaces is the DataContext and so the Itemssource for the TabControl.
<ContentControl Content="{Binding Path=Workspaces}" ContentTemplate="{StaticResource ResourceKey=WorkspacesTemplate}"/>
"How exactly is Content="{Binding Path=Workspaces}" creating a binding between ItemsSource of the TabControl and the Workspaces (the ObservableCollection of WorkspaceViewModel)?" Workspaces are the DataContext for the DataTemplate/TabControl and the ItemsSource is set to the DataContext.
<TabControl Margin="4" ItemsSource="{Binding}"
"The article says By relying on data binding, the Content property of a TabItem receives a ViewModelBase-derived object to display. How ?!?" i dont know the article, but i assume that Workspaces is a collection of object derived from ViewModelBase. every tabitem represent on item from the collection and so a viewmodelbase-derived object.

Is it possible to bind to a control's property from a datatemplate?

Ok, sounds odd, and there's likely a better way, but I haven't seen it yet.
What I'm trying to do is restyle a ListPicker under Windows Phone 7.
What I need is to
get rid of the header (that's easy, just define a null ListPicker.HeaderTemplate).
Force the picker to always go to full mode when clicked (again, easy, just set the ItemCountThreshold to 1).
Restyle the itemtemplate used when in FullMode (again, easy, just define a FullModeItemTemplate)
Incorporate the ListPicker's "HEADER" property value into the ItemTemplate (since only one item will ever show, i need the header text "embedded" within the one item).
It's that number 4 that I can't seem to get.
I've defined a listpicker like so (i'm directly defining the templates inline instead of in resources for now, just to keep things simple).
<phonekit:ListPicker Header="Header Text" x:Name="ListOfSounds"
SelectedItem="{Binding Path=DepartureChime, Mode=TwoWay, Converter={StaticResource EnumDescriptionToStringConverter}}"
ItemCountThreshold="1">
<phonekit:ListPicker.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Background="Transparent">
<TextBlock Text="{TemplateBinding Header}" />
<TextBlock Text="{Binding}" />
<TextBlock Text=">" />
</StackPanel>
</DataTemplate>
</phonekit:ListPicker.ItemTemplate>
Ignoring all the obvious formatting bits for now, the problem I'm having is that I can't use {TemplateBinding Header} from within a datatemplate. I've used it from a ControlTemplate no problem.
The result of this ItemTemplate should be an item displayed such as
{TextOfHeader}{Content of selected Item}>
I'm just not sure how to go about getting at a property of the templated control (the listpicker in this case).
Any ideas?
Take advantages of RelativeSource:
<TextBlock Text="{Binding Path=Header, RelativeSource={RelativeSource AncestorType={x:Type phonekit:ListPicker}}}" />

Silverlight Treeview SelectedItem TwoWay binding causing error in blend

I have a Treeview in a Silverlight 4 project, and I want to bind to its SelectedItem. When I do a binding to SelectedItem (Mode=TwoWay) its throwing an error in blend because SelectedItem is readonly, which is causing my XAML to not render. I don't ever want to SET the SelectedItem property, I just want to know when it changes via UI interaction. In WPF, I would just bind its SelectedItem using Mode=OneWayToSource, but Silverlight does not support that mode (afaik).
Treeview :
<controls:TreeView ItemsSource="{Binding Repository.MajorClasses}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}" />
Is there a workaround that anyone has used? And anyone know why OneWayToSource is omitted from Silverlight?
It's really readonly, so you cann't do that. You can use TreeView as base control and create CustomTreeView with implementation of bindable SelectedItem. Or create own behavior(attached property). Or use some third party control (f.i. telerik).
If you just want your VM to be informed when the user changes the selection, you should be able to do exactly what you are doing (a two way binding).
I have this working in Visual studio so, I suggest trying it from there, might just be a problem with Blend. VS intellisense doesn't suggest SelectedItem when typing in the XAML editor but that doesn't stop it from working.
The bound property in your VM is definately of the right type (MajorClass by the looks of it)?
What you need to do is make use of an Interaction Trigger and bind it to the SelectedItemChangedevent as follows:
<sdk:TreeView x:Name="ModuleNavigationItemWrappersTreeView" ItemsSource="{Binding ModuleNavigationItemWrappers}">
<sdk:TreeView.ItemTemplate>
<sdk:HierarchicalDataTemplate ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal" Margin="0,2,0,2">
<Image Source="/VanguardFinancials.Common;component/Images/icons/flag_blue.png" />
<TextBlock Margin="2,0,0,0" Text="{Binding ItemDescription}"></TextBlock>
</StackPanel>
</sdk:HierarchicalDataTemplate>
</sdk:TreeView.ItemTemplate>
<interactivity:Interaction.Triggers>
<interactivity:EventTrigger EventName="SelectedItemChanged">
<interactivity:InvokeCommandAction Command="{Binding TrackSelectedModuleNavigationItemWrapper}" CommandParameter="{Binding ElementName=ModuleNavigationItemWrappersTreeView}" />
</interactivity:EventTrigger>
</interactivity:Interaction.Triggers>
</sdk:TreeView>
Visit this for more information about Behaviors and Triggers. Hope this helps.

Silverlight: Can I create a custom button which contains two TextBlocks, each of which binds to a different property on an object?

I want to make buttons similar to those on this website.
Lets say that the object I'm working with is ArtPiece, and has a Title and Date. I want both of those to show up on my buttons in two different TextBlocks.
I've been trying to modify the button's ContentTemplate, then modifying the button's ContentPresenter inside the ContentTemplate, but I still can't get the TextBlocks to bind.
Any help getting this done entirely in XAML? I'm using Expression 3.
You want to do something like this:
<Button Click="Button_Click" Name="button" >
<Button.ContentTemplate>
<DataTemplate>
<StackPanel Background="Yellow" Width="200" Height="200">
<TextBlock Text="{Binding Title}" />
<TextBlock Text="{Binding Date}" />
</StackPanel>
</DataTemplate>
</Button.ContentTemplate>
</Button>
It sounds like what you really want is some sort of multi-binding support to bind these two properties to one Content property on the button. As far as I know there is no built in multi-binding support in silverlight as there is in WPF. This article outlines one approach to implementing it in silverlight.
If you were using the MVVM pattern a much easier approach would be to create another property in your ViewModel which concatenated the two strings together and then you could just bind the Content of the button to that single new property. This would be a much simpler and cleaner approach in my opinion.

Why does Path=SelectedItem.Content work for ComboBox in WPF but not Silverlight?

The following code works fine in WPF.
In Silverlight it gives me the error **Invalid attribute value {Binding ElementName=WhichNumber, Path=SelectedItem.Content} for property Text. **
How can I get this to work in Silverlight?
<ComboBox x:Name="WhichNumber" Width="100" HorizontalAlignment="Left" Margin="10" SelectedIndex="0">
<ComboBoxItem Content="One"/>
<ComboBoxItem Content="Two"/>
<ComboBoxItem Content="Three"/>
</ComboBox>
<TextBlock Text="{Binding ElementName=WhichNumber, Path=SelectedItem.Content}"/>
Silverlight doesn't support Relative Binding (binding the attribute of one element to the value of another element's attribute value) while WPF has full support for that kind of binding.
Or you could move to Silverlight 3 which introduces UI element to element binding :)
For some reason (why they did this is beyond me), the syntax is slightly different, instead of writing when using WPF:
<TextBlock Text="{Binding ElementName=WhichNumber, Path=SelectedItem.Content}"/>
you would write with Silverlight 3:
<TextBlock Text="{Binding ElementName=WhichNumber, SelectedItem.Content}"/>
so without the 'Path=' part.
Unfortunately the Silverlight people at Microsoft have a tendency to make small changes to syntax and other things, rather than striving for easy code reuse across WPF and Silverlight.

Resources