Code-behind static/dynamic properties in WPF and Naming Conundrum - wpf

I have a button defined in my XAML which has a button style and a vector graphic, it is defined thus:
<Button
Height="48"
Width="48"
mvp:Presenter.Action="CreateStudentApplication"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Grid.Row="5"
Grid.Column="3"
Style="{DynamicResource BaseButton2}">
<ContentControl Template="{StaticResource ApplicationVector}"/>
</Button>
In my code-behind, I have a method that dynamically adds new buttons similar to this one to a StackPanel. In brief, it does something to the tune of:
var button = new Button();
button.Height = 48;
button.Width = 48;
button.Tag = x.ID;
button.SetResourceReference(TemplateProperty, "ApplicationVector");
button.SetResourceReference(StyleProperty, "BaseButton2");
Now here's the weird part- It displays only the vector graphic, and no button behind it. When I remove the penultimate line (the line with the vector reference), it displays the button styled as it should be! I'm assuming that setting the template is overriding the style, however they seem to play amicably in XAML. I have also tried setting the ContentProperty instidead of TemplateProperty, but this resulted in a string of the type. Any ideas? Thank you!

Your XAML and code behind are not equivalent. In the XAML, you are setting the Content property of the button to be a ContentControl. In the code behind, you are setting the Template (or Content) property to be the ApplicationVector resource.
You would need to set the Content property of the button to be an instance of a ContentControl whose Template property is set to be your ApplicationVector resource.
var contentControl = new ContentControl();
contentControl.SetResourceReference(TemplateProperty, "ApplicationVector");
button.Content = contentControl;

Related

WPF Bind textbox Text to another control property [duplicate]

I have a situation where I need to create View box with one button. The xaml for this is as below: Please observe Width property of viewbox. The Width should be increased/decreased according to a slider bar(moving to right increases it, to left decreases it). As listed below I know how to do it in xaml and it works fine. But my requirement is to be able to create viewbox in code behind and assign it the properties.
<WrapPanel x:Name="_wrpImageButtons" Grid.IsSharedSizeScope="True"
ScrollViewer.CanContentScroll="True" d:LayoutOverrides="Height"
Margin="5">
<Viewbox x:Name="_ScaleButton"
Width="{Binding Value, ElementName=ZoomSlider}" Stretch="Fill">
<CustomButton:_uscVCARSImagesButton x:Name="_btnImage1"/>
</Viewbox>
</WrapPanel>
Thanks.
This should do what you want:
Viewbox x = new Viewbox();
Binding bnd = new Binding("Value") { ElementName = "ZoomSlider"};
BindingOperations.SetBinding(x, Viewbox.WidthProperty, bnd);
// ... Code to insert the Viewbox into the WrapPanel etc.
You can create the binding relatively easily in Code Behind:
var widthBinding = new Binding("Value") { ElementName = "ZoomSlider" };
_ScaleButton.SetBinding(FrameworkElement.WidthProperty, widthBinding);

Showing UserControl once at the time with DataTemplateSelector

I have a couple specific user controls to Show some Content, e.g. simple like Image, WebControl but also two complex specific custom controls drawing on a canvas.
Now I thought using the DataTemplateSelector to handle the different UserControls. I actully used this http://tech.pro/tutorial/807/wpf-tutorial-how-to-use-a-datatemplateselector as a reference.
I changed the code so the form loads the UserControls dynamically (according to the file extension) in the following collection:
ObservableCollection<string> _pathCollection = new ObservableCollection<string>();
The only difference to the reference is now I want to navigate back and forward to the next control by showing one control only at the time. Which control should I use instead of ListView?
<Grid>
<ListView ScrollViewer.CanContentScroll="False"
ItemsSource="{Binding ElementName=This, Path=PathCollection}"
ItemTemplateSelector="{StaticResource imgStringTemplateSelector}">
</ListView>
</Grid>
How do I need to bind it to the template (equal to ItemTemplateSelector above)? WPF is still very new to me and I am learning.
Use a ContentControl. Bind your current item to the Content-property and the DataTemplateSelector to the ContentTemplateSelector-property.
<ContentControl Content="{Binding Path=CurrentItem, Mode=OneWay}", ContentTemplateSelector="{StaticResource imgStringTemplateSelector}" />
Your CurrentItem should be a DependencyProperty or a INotifyPropertyChanged-property of your DataContext. When you change your CurrentItem, the ContentControl will update the template automatically with help of your TemplateSelector.

Binding inside ContentControl not working

I'm building a graphical designer, based upon an article by Sukram in CodeProject. I'm now trying to extend it so that each item on the canvas binds to a different ViewModel object - i.e. I'm setting the DataContext for each item.
Every item on the designer is actually a ContentControl, into which is placed a different template (based upon which toolbox item was dragged onto the canvas). So I have a template containing a TextBox, and I have a ViewModel object containing a Name property, and I bind the Text property of the TextBox to the Name property of the ViewModel, and ... nothing. I've checked the visual tree with Snoop, and it confirms that the DataContext of the TextBox is the ViewModel object. Yet the TextBox remains empty. And if I modify the (empty) Text in the TextBox, the Name property in the ViewModel does not change. So it looks like the binding is not being applied (or has been removed somehow).
I've found a few posts which talk about the ContentControl messing around with the DataContext and Content properties, but I'm not sure how applicable they all are. The code sets the ContentControl.Content as follows:
newItem = new ContentControl();
ControlTemplate template = toolbox.GetTemplate();
UIElement element = template.LoadContent() as UIElement;
ViewModelItem viewModel = new ViewModelItem() { Name = "Bob" };
newItem.Content = element;
newItem.DataContext = viewModel;
and the XAML for the template is:
<ControlTemplate>
<Border BorderBrush="Black" BorderThickness="1" Width="100">
<TextBox Text={Binding Name}/>
</Border>
</ControlTemplate>
Snoop shows that the TextBox has a DataContext, and if I Delve that DataContext I can see that it has a Name property whose value is "Bob". So why does the TextBox remain empty? Snoop allows me to change that Name property, but the TextBox remains empty.
What am I doing wrong?
A few more details. I've set the VS2010 Debug DataBinding option for the OutputWindow to Verbose, which seems to show that the binding is all being attempted before I set the DataContext. Is it possible that the change to the DataContext is not being recognised?
I've just found this post DataTemplate.LoadContent does not preserve bindings - apparently DataTemplate.LoadContent does not preserve bindings. So it looks like I have to write my own version of LoadContent().
I've realised that the template has come through a XamlWriter, which apparently strips all bindings. This wouldn't be helping.
I've not been able to fix the DataTemplate.LoadContent(), but I realised that I didn't actually need a DataTemplate, since the XamlWriter / XamlReader was already instantiating the UI element that I was after. I found a fix to make the XamlWriter write all the bindings here, and after that it all works.
Thanks for your help.
Maybe you need to tell the binding in the ControlTemplate to look at the TemplatedParent, as is mentioned in this thread?
<TextBox Text="{Binding Path=Name, RelativeSource={RelativeSource TemplatedParent}}"/>
Either that, or try to use a DataTemplate instead.
I can't test this at the moment, so I might just be guessing here.
I would use a DataTemplate, as bde suggests.
You are trying to put some UI on your own data (ViewModel), and this is what Data-Templates are meant for (ControlTemplate is usually what you use if you want to change how e.g. a Button looks).
Change your code to use ContentControl.ContentTemplate with a DataTemplate:
<DataTemplate>
<Border BorderBrush="Black" BorderThickness="1" Width="100">
<TextBox Text={Binding Name}/>
</Border>
</DataTemplate>
Code-behind:
newItem = new ContentControl();
//NOTE: .GetTemplate() needs to return a DataTemplate, and not a ControlTemplate:
newItem.ContentTemplate = toolbox.GetTemplate();
ViewModelItem viewModel = new ViewModelItem() { Name = "Bob" };
newItem.Content = viewModel;
newItem.DataContext = viewModel;

WPF Adorner Visibility Data Binding programmatically

I'm creating a Loading Adorner that has a swirling icon over it. I tried binding the visibility property directly in the XAML but that actually hides everything inside its hierarchy.
I have this in my XAML:
<AdornerDecorator Visibility="{Binding Path=RootGroup.Loading, Converter={StaticResource VisibilityConverter}}">
<TreeView x:Name="groupTreeView" />
</AdornerDecorator>
and this in my constructor
LoadingAdorner adorner = new LoadingAdorner(groupTreeView);
AdornerLayer.GetAdornerLayer(groupTreeView).Add(adorner);
This isn't want I wanted so I tried binding it in the code instead:
LoadingAdorner adorner = new LoadingAdorner(groupTreeView);
Binding bind = new Binding("RootGroup.Loading");
bind.Source = this.DataContext;
bind.Converter = new VisibilityConverter();
adorner.SetBinding(LoadingAdorner.VisibilityProperty, bind);
AdornerLayer.GetAdornerLayer(groupTreeView).Add(adorner);
This will work if the DataContext is not null because it can actually find RootGroup.Loading. But if it is null then the binding has no source to look at.
So I was wondering what does the XAML databinding use as its .Source ? Binding directly in the XAML binds to the correct property, but it doesn't achieve the same result. So I'm just wondering what I should be setting my .Source to So i can bind to RootGroup.Loading ?
Thanks,
Raul
This doesn't directly answer your question, but why are you using an adorner to get the loading animation effect.
Why not just use a border element that is a sibling of your TreeView that is Z-Ordered on top and then do your animation in that.
So you do something like this
<Grid>
<TreeView />
<Border x:Name="myBorder">... </Border>
</Grid>
Then you can do all your binding in XAML without hiding the entire Visual Tree.

Silverlight button style

I am trying out new styles with silverlight, and I created a new button skin with blend that consists of a border and a textblock. Wondered if there is a way to change the the text of the textblock when the the button's content(text) property is changed.
The binding would look like this:
<TextBlock Text="{TemplateBinding Content}"/>
The problem is when I try to set the content to something other than text:
<Button>
<Button.Content>
<Rectangle Fill="#FFB51111"/>
</Button.Content>
</Button>
In this case using the ContentPresenter would work better. It uses the same binding expression, but can display more than text. But all that is really up to you.
I don't really get what your trying to do. Normally, you include a TextBlock like that as a part of the button content.
Use a ContentPresenter rather than a TextBlock in your Template.

Resources