I have a Silverlight 3 Label which I connect to a ComboBox using the Target Property of the Label. According to MSDN the Label class iterates through the targets bindings and searches the sources for meta data to determine the content of the Label.
This actually works as long as the target is a standard control. But if I use a custom control, which in my case extends ComboBox, and introduce a new DependencyProperty it is simply ignored.
E.g. this works:
<dataInput:Label Grid.Row="3" Grid.Column="0"
Target="{Binding ElementName=cbxCountry}"
VerticalAlignment="Center"/>
<ComboBox x:Name="cbxCountry" DisplayMemberPath="Name"
SelectedItem="{Binding DataModel.Country, Mode=TwoWay}"
ItemsSource="{Binding Countries, Source={StaticResource ApplicationData}}"/>
In the above example the SelectedItem Binding is searched and DataModel.Country does contain the DisplayName which is taken.
But this does not:
<dataInput:Label Grid.Row="3" Grid.Column="0"
Target="{Binding ElementName=cbxCountry}"
VerticalAlignment="Center"/>
<local:MyComboBox x:Name="cbxCountry" DisplayMemberPath="Name"
MySelectedItem="{Binding DataModel.Country, Mode=TwoWay}"
MyItemsSource="{Binding Countries, Source={StaticResource ApplicationData}}"/>
The custom Properties are Dependency Properties and declared as follws:
private static readonly DependencyProperty MySelectedItemProperty =
DependencyProperty.Register("MySelectedItem",
typeof(object), typeof(MyComboBox),
new PropertyMetadata(null,
MySelectedItemPropertyChanged));
I know that I can work around this by defining the PropertyPath on the Label, but I'd rather avoid this, if possible.
So my question now is, can anyone reproduce this issue, and much more important of course, does anybody know how to solve it? :-)
Thanks, Markus
Ok, in case anyone runs into the same problem, here is the solution: Just change the visibility of the DependencyProperty from private to public.
Quite obvious actually... :-/
Related
I can't seem to pick my way through Telerik's terrible documentation for binding through an MVVM situation. We've got the standard view, and view model. The viewmodel exposes a property, 'Body' that is supposed to represent what the user is typing. Here are the relevant lines of xaml:
<telerik:DocxDataProvider
x:Name="DocxProvider"
RichTextBox="{Binding ElementName=editor}"
Docx="{Binding Body, Mode=TwoWay,
UpdateSourceTrigger=LostFocus}" />
<telerik:RadRichTextBox
Grid.Row="1"
x:Name="editor"
Margin="0"
AllowDrop="True"
ShowComments="False"
MinWidth="800"
MinHeight="300"
MaxWidth="1024"
MaxHeight="1200"
HorizontalAlignment="Left"
HorizontalContentAlignment="Left"
Width="790"
Padding="20,20,0,20"
TabIndex="10"
Cursor="IBeam"
IsSpellCheckingEnabled="True" >
</telerik:RadRichTextBox>
But when I set a break point on Body, it never gets hit. What property do I need to bind to so that my view model actually gets the content of the text box?
Have you tried binding to Rtf property of telerik:RadRichTextBox; another thing can be the ordering of your elements, can you try declaring <telerik:RadRichTextBox before <telerik:DocxDataProvider
Also have a look at this thread on telerik forum -
http://www.telerik.com/community/forums/wpf/richtextbox/binding-document.aspx
Did you remember to set the datacontext in the constructor of the xaml.cs file:
public View(ViewModel viewModel)
{
InitializeComponent();
DataContext = viewModel;
}
This is how you hook up the viewmodel to the view.
I have created an attached behavior that is used to execute a Delegate of type Func<bool> when the behavior is invoked. Below is the dependancy property definition.
public static readonly DependencyProperty SendToDetailBehaviorProperty = DependencyProperty.RegisterAttached("SendToDetailBehavior", typeof(Func<bool>), typeof(ListDetailAspectSendToDetailBehavior), new UIPropertyMetadata(null, SendToDetail));
I have it working just as expected however in my XAML I get the following error, preventing the designer from loading.
Property 'SendToDetailBehavior' was
not found or is not serializable for
type 'SortableListView'
Below you will find the xaml.
<Controls:SortableListView Grid.Row="0"
Grid.Column="0"
Name="lvwLocations"
MinHeight="150"
MinWidth="{Binding Path=BusinessObject.Locations, ValidatesOnDataErrors=true, Converter={StaticResource AlwaysReturn1Converter}, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
Style="{DynamicResource SortableListViewStyle}"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
IsSynchronizedWithCurrentItem="True"
**behaviors:ListDetailAspectSendToDetailBehavior.SendToDetailBehavior="{Binding Path=LocationListDetail.SendFocusToDetail}"**
ItemsSource="{Binding Path=LocationListDetail.MasterList}"
SelectedItem="{Binding Path=LocationListDetail.DetailItem, Mode=TwoWay}"
MouseDoubleClick="lvwLocations_MouseDoubleClick">
If I change the underlying type of the Dependancy Property to a bool for example, the error goes away.
As I said the attached behavior is working, only the designer blows up. I have looked for documentation on this and have come up empty. I am hoping someone here has some insight.
Thanks,
BDN
Instead of using delegate, change your dependency property type to Command (I used the DelegateCommand) which will wrap the delegate inside it. I was having the same problem as yours, but it was solved by this method.
Is this happening in VS 2008, 2010, or Expression Blend? The VS2008 designer is notoriously fragile. As far as fixing it, have you tried using a non-generic delegate type? Something like so:
public delegate bool SendToDetail();
And then your VM would expose a property of that delegate type instead of Func<bool>.
I have another WPF databinding question... one that I haven't found an answer to anywhere, and this surprises me since it seems like it is very basic.
Essentially, I have a string in code behind that I would like to establish a two-way binding with with a textbox in my GUI. I thought it was a simple matter of creating a DependencyProperty in the code behind, and then tying it to the TextBox via a Source binding. The problem is, I can't get one or both parts right.
Here is my DependencyProperty definition from the code behind:
public static readonly DependencyProperty FilePathProperty = DependencyProperty.Register( "FilePath", typeof(string), typeof(Window1));
public string FilePath
{
get { return (string)GetValue(FilePathProperty); }
set { SetValue( FilePathProperty, value); }
}
And here is my XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ReportingInterface Test Application" Height="300" Width="536">
<Menu DockPanel.Dock="Top">
<MenuItem Name="menu_plugins" Header="File">
<MenuItem Header="Open">
<StackPanel Orientation="Horizontal">
<Label>File location:</Label>
<TextBox Name="text_filepath" Width="100" Text="{Binding Source=FilePath, Path=FilePath, Mode=TwoWay}"></TextBox>
<Button Margin="3" Width="20">...</Button>
</StackPanel>
</MenuItem>
</MenuItem>
</Menu>
The part I know is obviously wrong is the Binding part... I hate to waste people's time here with this question, but I honestly have come up short with every search (but now at least this request will populate subsequent google searches). :)
Thank you!
When you defined a binding in XAML, it binds to whatever is set as the DataContext for the object (or it's parent).
This typically means you'd set the DataContext of the Window to some class, and then the binding will work:
<TextBox Name="text_filepath" Width="100" Text="{Binding Path=FilePath, Mode=TwoWay}" />
You can fix this by adding, in the Window's constructor:
this.DataContext = this;
That will make the binding work against the window itself.
Alternatively, you can setup the binding to bind against a specific source object. If, in this case, you wanted to be able to use something else as the DataContext, but still want to bind to a Dependency Property defined in your Window, you could do:
<TextBox Name="text_filepath" Width="100" Text="{Binding Path=FilePath, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"></TextBox>
This works by telling the binding to find the first ancestor of type "Window", and bind it the "FilePath" property on that object.
For what it's worth, I would recommend looking into the M-V-VM pattern (Model, View, ViewModel)- essentially, what you do is have this class that serves as the DataContext for your XAML, and all your fun exposed properties/commands/what have you are exposed as public members of that class (called a ViewModel).
Here's a good overview webcast:
MVVM video
And here's another from MSDN mag:
http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
I'll preface this and say that I'm new to Silverlight development by about week so I'm most likely doing it wrong...
Anyway I have a Label and a TextBox done up thusly in XAML:
<dataInput:Label Target="{Binding ElementName=JobCode}" Height="18" HorizontalAlignment="Left" Margin="15,7,0,0" Name="lableJobCode" VerticalAlignment="Top" Width="250" FontWeight="Bold" Grid.Column="1" />
<TextBox Height="23" Text="{Binding SelectedRole.Job_Code}" HorizontalAlignment="Left" Margin="15,31,0,0" Name="JobCode" VerticalAlignment="Top" Width="277" Grid.Column="1" IsReadOnly="{Binding IsNotAdmin}" />
Everything works great, the only issue I have is that the binding I'm doing on the IsReadOnly attribute which goes to a boolean in my ViewModel which is set based on a call to an authentication service, is now overriding the label Content to the name of my ViewModel property: IsNotAdmin. I can't seem to find a way to specify which data binding source to pull the label content MetaData from. Maybe I'm missing something on how to manipulate control editablity/visibility from my ViewModel.
--Update: The data source class that the TextBox is bound to is as follows (for the relevant parts):
public class RoleSummary {
[Display(Name= "Job Code (To be Completed by HR):")]
public string Job_Code { get; set; }
Without the binding to the IsReadOnly attribute the Label displays the text from the data annotation just fine. When I add the binding it displays "IsNotAdmin"
can you post more of your code? I'm not entirely sure what it is that you're trying to make happen so it's hard to propose a solution.
I assume you're trying to create a text entry element that has validation performed on it (hence the label) -- but what exactly is the label supposed to be showing for it's content?
EDIT: I figured this out. The label control by default looks through all the properties in its datacontext looking for metadata it can use. For whatever reason it decided to use the metadata for the IsNotAdmin property in your code (even though you didn't set it manually, I assume that the Display metadata gets a default value of the property name), and so you get that for the text of the label.
Microsoft put in a property specifier into the data controls so you can tell it which property it should use for the metadata lookup: PropertyPath
Try it like this:
<dataInput:Label Target="{Binding ElementName=JobCode}" PropertyPath="SelectedRole.Job_Code" Height="18" HorizontalAlignment="Left" Margin="15,7,0,0" Name="lableJobCode" VerticalAlignment="Top" Width="250" FontWeight="Bold" Grid.Column="1" />
<TextBox Height="23" Text="{Binding SelectedRole.Job_Code}" HorizontalAlignment="Left" Margin="15,31,0,0" Name="JobCode" VerticalAlignment="Top" Width="277" Grid.Column="1" IsReadOnly="{Binding IsNotAdmin}" />
As long as your datacontext is right (which it should be) this should work for you -- it worked in my sample I reconstructed from your code.
I'm trying to make an Address control that has an IsReadOnly property, which will make every TextBox inside read only when set to true.
<my:AddressControl Grid.Column="1" Margin="5" IsReadOnly="True"/>
I've managed to do this just fine with a dependency property and it works.
Here's a simple class with the dependency property declared :
public partial class AddressControl : UserControl
{
public AddressControl()
{
InitializeComponent();
this.DataContext = this;
}
public static readonly DependencyProperty IsReadOnlyProperty =
DependencyProperty.Register("IsReadOnly", typeof(bool),
typeof(AddressControl), null);
public bool IsReadOnly
{
get { return (bool)GetValue(IsReadOnlyProperty); }
set { SetValue(IsReadOnlyProperty, value); }
}
}
In the XAML for this codebehind file I have a Textbox for each address line:
<TextBox IsReadOnly="{Binding IsReadOnly}" Text="{Binding City, Mode=TwoWay}"/>
<TextBox IsReadOnly="{Binding IsReadOnly}" Text="{Binding State, Mode=TwoWay}"/>
<TextBox IsReadOnly="{Binding IsReadOnly}" Text="{Binding Zip, Mode=TwoWay}"/>
Like i said this works just fine.
The problem is that the Address control itself is bound to its parent object (I have several addresses I am binding).
<my:AddressControl DataContext="{Binding ShippingAddress, Mode=TwoWay}" IsReadOnly="True">
<my:AddressControl DataContext="{Binding BillingAddress, Mode=TwoWay}" IsReadOnly="True">
The problem is that as soon as I set DataContext to something other than 'this' then the binding for IsReadOnly breaks. Not surprising because its looking for IsReadOnly on the Address data entity and it doesn't exist or belong there.
I've tried just about every combination of binding attributes to get IsReadOnly to bind to the AddressControl obejct but can't get it working.
I've tried things like this, but I can't get IsReadOnly to bind independently to the AddressControl property instead of its DataContext.
<TextBox IsReadOnly="{Binding RelativeSource={RelativeSource Self}, Path=IsReadOnlyProperty}" Text="{Binding City, Mode=TwoWay}" />
I think I'm pretty close. What am I doing wrong?
With this answer (actually my own answer to a similar question) I have a good [better] solution.
I still have to iterate through the textboxes, but I don't have to set the actual value. I can create bindings in the codebehind - just not with XAML.
I think you're stuck, at least, if you want to do this just via binding. My guess is that you're going to have to resort to code-behind, presumably by iterating through your child textbox controls and setting their IsReadOnly propert as a side-effect of your Address control's IsReadOnly property.
Unlike some folks who think that any code sitting in a code-behind file is effectively an admission of failure, I don't get religious about it: if throwing some code into a code-behind is the easiest way to do something, that's where I put my code. On the contrary, if I have to spend half a day trying to figure out how to do something via binding that I could do in five minutes with a code-behind, that's failure, IMO.