I'm developing an application using C# and XAML and I've encountered a problem that is confusing me. I have a property in my data called GroupImage and have used binding to set the Source property of an Image with it. That worked fine but when I wanted to do the same thing a second time it doesn't show the image in the second Image control.
<Image Source="{Binding Group.GroupImage}" Width="250" Height="500" Stretch="UniformToFill" />
<Image VerticalAlignment="Bottom" Stretch="UniformToFill" Source="{Binding Group.GroupImage}" Grid.RowSpan="2"/>
The top one works fine the bottom one doesn't. I have been reading about Data Binding and have gotten the impression that you need to specify something in the DataContext to use a property more than once. Is this right? It seems a very strange way of doing this.
I am relatively new to C# so sorry if I'm missing something obvious. I'd appreciate a more knowledgeable cluing me in.
Thanks
Update Following the assistance I received I figured out that the context was being set to
DataContext="{Binding Group}"
And as a result my second line needed to change to the following since the Data Context was already set to Group.
<Image VerticalAlignment="Bottom" Stretch="UniformToFill" Source="{Binding GroupImage}" Grid.RowSpan="2"/>
You don't need to specify something in the DataContext to use a property more than once. But your two Image have to have the right DataContext (you can easily test it with the debugger), depending on their location on the visual tree (You didn't provide any code for the DataContext part ?) .
You can also check that your Image's Width/Height are not 0.
Related
In my WPF app we are using an adorner for displaying validation messages, in the particular case there is a single row grid that has multiple controls some of which have validation. The problem I'm having is that I want to force the width of the error message control to be the same as the grid but can't seem to find a way to reference that grid from the adorner template. Here is a sample of what I tried:
<ControlTemplate x:Key="Local_TopAdornedTemplateWide">
<StackPanel>
<AdornedElementPlaceholder x:Name="adornedElement"/>
<TextBlock MaxWidth="{Binding Path=ActualWidth, RelativeSource={RelativeSource FindAncestor, AncestorType=Grid}, ElementName=adornedElement}"
TextWrapping="Wrap"
Text="{Binding Converter={StaticResource Local_ValidationErrorMessageConverter}}"
Style="{DynamicResource Error_Text}"
Padding="2 1 0 0"
Visibility="{Binding ElementName=adornedElement, Mode=OneWay, Path=AdornedElement.IsVisible, Converter={StaticResource BooleanToVisibilityConverter}}"
/>
</StackPanel>
</ControlTemplate>
This causes the application to crash with an XamlParseException.
Ideally the solution would not be specific to a grid so that it would get the width of any container type, but for now grid is the only use case.
Edit:
Here is an example of another template we use in the application; this template would not work for my case as it would limit the error to be the width of a single column of the aforementioned grid:
<ControlTemplate x:Key="Local_TopAdornedErrorTemplate">
<StackPanel>
<AdornedElementPlaceholder x:Name="adornedElement"/>
<TextBlock MaxWidth="{Binding ElementName=adornedElement, Path=ActualWidth}"
TextWrapping="Wrap"
Text="{Binding Converter={StaticResource Local_ValidationErrorMessageConverter}}"
Style="{DynamicResource Error_Text}"
Padding="2 1 0 0"
Visibility="{Binding ElementName=adornedElement, Mode=OneWay, Path=AdornedElement.IsVisible, Converter={StaticResource BooleanToVisibilityConverter}}"
/>
</StackPanel>
</ControlTemplate>
Using snoop I captured the following two screenshots (I could not take one of the full stack to prevent posting anything proprietary)
This shot shows the grid I mentioned previously, within this it is the FinancialTextBox item that is being adorned
This shot shows two things, the item selected in blue is the highest ancestor of the grid in the previous shot, the yellow highlight is the Textbox from the content template
With those two it seems to be apparent that (based on information from Contango's answer) the two items aren't not in the same visual tree which would lead me to believe my question is not possible. However the second template I added (which does work) points that at least some visual information from the adorned element lives on in the place holder.
So now my question boils down to a) does this information include the parent of the adorned element and b) how can this be accessed via a binding on a different element?
This ended up being a lot simpler than the path I was trying to go down.
I was doing some reading on the AdornedElementPlaceholder class and came across this entry on MSDN and noticed that the class actually has a property called parent, with that I tried the following binding and it works perfectly:
MaxWidth="{Binding ElementName=adornedElement,
Mode=OneWay,
Path=AdornedElement.Parent.ActualWidth}"
WPF is quite powerful and flexible.
You can bind any property in any XAML tag to any property in any other XAML tag.
For example, you could write a test app that binds the Text property of an input box to the Text property of a label, so as you type something into the text box, the label would change automatically (assuming you use UpdateSourceTrigger=PropertyChanged). This is a direct XAML to XAML binding, with no C# in sight.
Similarly, you could bind the width of your error box to the width of the parent control, whatever that may be.
Google RelativeSource and AncestorType, this is a great link:
http://druss.co/2013/10/wpf-binding-examples/
See if you can grok how the Visual Tree and Logical Tree works in WPF, once you understand that, you will understand more of how binding works.
I'd also recommend using the free tool Snoop to look at the Visual Tree. XAML Spy is excellent, but not free.
Snoop can tell you if there is anything that has a bad binding at runtime (you set the filters up, and it will list all bad bindings).
You can use Snoop to get the full XAML path of your source (the XAML you wrote above), then get the full XAML path of the target (i.e. the ActualWidth of your Grid), then compare them: it may be quickly apparent that one is not the ancestor of the other, as they are on different branches of the visual tree, or that there is some other issue which is preventing a simple walk up the visual tree from working.
If you just want to get something working, as a proof of concept, try naming the target XAML grid using x:Name, and reference it by name instead of AncestorType.
I am trying to create an application to take notes for windows phone 8.1
I want to give the user,a notebook type of feel.
For this I have created the UI for notes, the XAML is:
<Grid Margin="0,12.333,0,-0.333">
<Grid.Background>
<ImageBrush ImageSource="Images/notebookpaper.jpg"/>
</Grid.Background>
<TextBox TextWrapping="Wrap" Background="{x:Null}" Text="" BorderBrush="{x:Null}" HorizontalAlignment="Left" Margin="60,96,0,0" VerticalAlignment="Top" Height="480" Width="340" BorderThickness="0" GotFocus="TextBox_GotFocus" LostFocus="TextBox_LostFocus" FontFamily="Arial" TextChanged="TextBox_TextChanged" AcceptsReturn="True" FontSize="24.8"/>
<TextBlock Text="Date : " HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top" Margin="246,10,0,0" Height="20" Width="59"/>
</Grid>
The image notebookpaper.jpg looks like this:
When user types in the text in text box, it looks like:
The problem is that, some characters appear a little above the line, some exactly on the line etc. which looks odd. Also, when I try to scroll, UI appears as:
The text appears striked out, as only the text scrolls and not the background image.
Also I want to be able to provide user a list of 5-6 fonts out of which they can select which one to use for typing the notes.
What should I do, so that the text appears properly aligned and text scrolls properly.
Is there any other way to do this ?
It looks like you have two problems:
Varying line height
Scrolling doesn't match the lines
To solve the first problem, you can probably work with TextBlock.TextLineBounds, talked about a bit in this MSDN blog post and the TextLineBounds enumeration documentation. This only seems to apply to TextBlocks, so you might have to swap between a TextBlock and TextBox as users edit their text.
To solve the second problem, the TextBox styles and templates page has a lot of helpful info. It looks like you can make your ImageBrush the background of your control by overriding TextBoxButtonBackgroundThemeBrush. If that doesn't work when focused, you may have to take the entire template given on the linked page and edit it to put your image in the background (there's a lot of XAML, but you should just be able to put your image in BackgroundElement or just before it).
If it still doesn't scroll, you can try setting ScrollViewer.Background instead; if that doesn't work, you'll need to handle the ScrollViewer.ViewChanging or ScrollViewer.ViewChanged events (probably by overriding it) so that it you can transform the background image by the amount of pixels the scrollviewer has moved.
You can also find the ScrollViewer in your code-behind (and skip dealing with the template) by using VisualTreeHelper. This would allow you to set the background of the ScrollViewer and/or subscribe to its events. This however is more brittle than the other methods and is usually a last resort.
I am currently having an issue regarding this component.
This is the xaml usage of it in my app:
<telerikPrimitives:RadPickerBox x:Name="box_change" Width="0">
<StackPanel Background="White">
<StackPanel Height="618">
<PasswordBox Name="NewPassword1" Padding="2,8,2,8" Margin="10,0,10,0" Style="{StaticResource PasswordBoxStyle}" />
</StackPanel>
</StackPanel>
</telerikPrimitives:RadPickerBox>
I am currently in need of retrieving, from my C# code, the value "password" of the field "NewPassword1", still I am unable to do that.
I already tried retrieving it with something like this:
box_change.NewPassword1.Password
but, of course, else I wouldn't be asking this question right now, this way doesn't work.
What would you suggest to retrieve the value?
Thanks in advance,
Guido
this.NewPassword1.Password
Glad to help!
Have you considered using Telerik's RadPasswordBox for WP8? It's optimized for passwords with masking characters and other features (and easily provides you with the password):
var userEnteredPassword = myPasswordBox.Password;
That being said, even though your PasswordBox is the child of two StackPanels, you can access the Password box in the same scope via NewPassword1. If you have more complex controls see the control's documentation on how to get the value of a child element.
I have a very odd error case that sprung up the moment I used a StaticResource converter on a Rectangle for coloring its background and at the same time using a MouseDown handler on another component next to it within a DataTemplate. If I narrow the code down a bit, this is what is required to reproduce the error :
In the top I have these resources, one pointing to a converter that takes the boolean from the binding and converts it to a fill background color):
<Window.Resources>
<vm:DesktopViewModel x:Key="DesktopVM" />
<vm:BooleanToColorConverter x:Key="converter" />
</Window.Resources>
And later in the same xaml file I iterate over a list of Alarm objects using this (I have replaced a Grid layout with a StackPanel and removed some other components for shorter code sample, this code snippet below still fails):
<ItemsControl ItemsSource="{Binding Alarms}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Rectangle Height="20" Stroke="Black" Width="20" RadiusX="4" RadiusY="4" Fill="{Binding Alarm, Converter={StaticResource converter}}"/>
<Image Source="/MyNamespace;component/images/chart.png" Stretch="None" MouseDown="Image_MouseDown" Cursor="Hand"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
If I remove the MouseDown handler on the image it runs just fine without the nullpointer error in the start. If I remove the Fill tag in the Rectangle the code works just fine WITH the MouseDown handler!!! (and the handler works just fine too). It seems like the StaticResource reference in Fill is messing up something that makes locating the mouse handler function fail?!?
Note that it fails when the window is created, not while running or clicking anything.
Edit: I had the same nullpointer issue if I replaced the converter with a style using a StaticResource with triggers to do the same as the converter. Its pretty clear that the StaticResource reference in an attribute is the culprit but I have no idea why it should affect the event listener.
Also the order of the compoents dont matter either. If I place the Image before the Rectangle the error is exactly the same.
My guess is that the problem is in your converter code, that it does not take into account that it can get a null value.
Why the effect of the mouseDown? Probably it causes the rendering of the image element at an earlier moment and to request the value of the Fill property at a moment that your ViewModel has not been created yet.
There is too little information to state it with certainty, but converters that do not handle null values properly can be a major pain in WPF development in my experience. A lot of design time instability has had root in converters that did not handle the null values properly.
I have defined a DataTemplate for a ListBox. Inside the template, I use TextBlock controls to display the properties of the data context. For example:
<TextBlock Text="{Binding Path=FirstName}" />
And if I do this:
<TextBlock Visibility="{Binding Path=IsAccountValid}" />
...the application runs, but there is a warning in the output about trying to bind a boolean property to a Visibility enumeration.
If I do this:
<TextBlock Visibility="{Binding Path=IsAccountValid,Converter={StaticResource visibilityOfBool}}" />
and somewhere in my App.xaml is:
<BooleanToVisibilityConverter x:Key="visibilityOfBool" />
I get a null reference exception.
I suspected this might be because the property IsAccountValid is not a dependency property, so I added a CheckBox to the window, and did this:
<TextBlock Visibility="{Binding Path=IsChecked,Converter={StaticResource visibilityOfBool},ElementName=butA}" />
But got the same error.
Why? The DataContext object is valid because if I bind IsAccountValid to the Text property, the value is correctly displayed.
The converter is never called, so I am wondering if it is the converter that cannot be found.
Why can the converter not be found? Why can the converter be found outside the data template and not inside the data template?
I tried building the template again with Blend, as Blend usually gets it right, but the code it generated was the same as mine.
I tried some of the fixes suggested on this website, including setting RelativeSource to TemplateParent and Self, but it made no difference.
What is going on?
We use such converter all the time in our Data Templates. Do you define the converter key inside your resource dictionary? Merge another Resource Dictionary?
The IsAccountValid property doesn't have to be a dependency property. If the converter couldn't be found then you wouldn't be able to open the form. You have the right approach using the converter but it is difficult to say exactly what is causing the exception without seeing more information.
As Amittai and Chris pointed out, it seems that you're headed in the right direction. I know it sounds a bit stupid, but try to add a space between the comma and the Converter= statement in the binding. Like so:
<TextBlock Visibility="{Binding Path=IsAccountValid, Converter={StaticResource visibilityOfBool}}" />
On some systems there are weird symptoms when there's no space after the comma. I couldn't find the actual reason for that.
Thank you all for your help in my investigation.
I have solved the problem.
These two lines of code are included in the DataTemplate, one is a TextBlock, and one is a hyperlink:
<TextBlock Text="Hello" Visibility="{Binding IsChecked,ElementName=chkBox,Converter={StaticResource visibilityOfBool}}" />
and
<TextBlock Grid.Column="1" >
<Hyperlink Click="ProgHomePageHyperlink_Click" >
<TextBlock Text="{Binding Path=Title}" />
</Hyperlink>
</TextBlock>
When they are both included in the code, the runtime throws a null reference exception.
But if I comment one of them out, either the TextBlock or the HyperLink, everything runs ok.
If I remove the Click handler from the hyperlink, everything runs ok.
If I comment out the converter in the TextBlock, the application runs, but I get a mismatched binding warning, which is well deserved.
So, including a Click handler in the hyperlink means the converter in the TextBlock cannot be found.
How weird is that!