Silverlight 4, SetBinding not working - silverlight

I want to bind the contents of a HyperlinkButton to a resource programmatically, it't not working. This is the code I have so far:
HyperlinkButton Link1 = new HyperlinkButton();
Link1.Style = Application.Current.Resources["LinkStyle"] as Style;
Link1.NavigateUri = new Uri("/Home", UriKind.Relative);
Link1.TargetName = "ContentFrame";
Binding b = new Binding("TabTitles.HomePageTitle");
b.Source = this.Resources["ResourceWrapper"];
Link1.SetBinding(HyperlinkButton.ContentProperty, b);
I get a MethodAccessException

The MethodAccessException is commonly thrown when the public access modifier is missing from a member you want to access. Have you tested the TabTitles property of whatever is held in the "ResourceWrapper" resource? Have the then tested the HomePageTitle property of whatever TablTitles returns?
Note also that if HomePageTitle returns a UIElement you can only place that value once in the visual tree, however my guess is its a string.

Related

trouble displaying flowdocument

I'm having some problems displaying the contents of a flowdocument in a flowdocumentscrollviewer. I create a generic list that holds a class which contains an int, string and a flowdocument.
In a WPF listbox, I am trying to display the flowdocument in the scrollviewer alongside a button. I use the following function called from the WPF window constructor to populate the listbox
private void populateListBox()
{
foreach(Element el in _notesList)
{
StackPanel sp = new StackPanel();
sp.Orientation = Orientation.Horizontal;
Button b = new Button();
b.Content = el._theID;
sp.Children.Add(b);
FlowDocumentScrollViewer fdsv = new FlowDocumentScrollViewer();
fdsv.MinWidth = 400;
fdsv.Document = el._theDoc;
sp.Children.Add(fdsv);
ListBoxItem lbi = new ListBoxItem();
lbi.Content = sp;
noteList.Items.Add(lbi);
}
}
But the code does not work. There are no errors but the scrollviewers are just blank in the listbox. I also tried storing the classes in an ObservableList and binding to the Document property but that didn't work either.
Any ideas what is happening?
Nevermind. I figured it out.
Further down in the program execution I was copying the flowdocument blocks to a merged document in a foreach statement. This doesn't work even if you use Blocks.ToList(). I eventually found a way to copy the document contents to another document here.

Silverlight Image Data Binding

I am new to Silverlight, and have an issue with binding.
I have a class ItemsManager, that has inside its scope another class Item.
class ItemsManager
{
...
class Item : INotifyPropertyChanged
{
...
private BitmapImage bitmapSource;
public BitmapImage BitmapSource
{
get { return bitmapSource; }
set
{
bitmapSource = value;
if(PropertyChanged != null )PropertyChanged("BitmapSource")
}
}
}
}
I do the following in code to test binding:
{
ItemsManager.Instance.AddItem("123");
//Items manager started downloading item visual
//part (in my case bitmap image png)
Binding b = new Binding("Source");
b.Source = ItemsManager.Instance.GetItem("123").BitmapSource;
b.BindsDirectlyToSource = true;
Image img = new Image();
img.SetBinding(Image.SourceProperty, b);
img.Width = (double)100.0;
img.Height = (double)100.0;
LayoutRoot.Children.Add(img);
}
Once image is loaded, image doesn't appear. Though, if I set directly after image has been loaded its source, it displays well.
I also noticed that PropertyChanged("BitmapSource") never fires, because PropertyChanged is null, like Image never binded to it.
I am looking forward to hearing from you!
PropertyChanged("BitmapSource") fires in case of two-way binding.
I.e. if you use two way binding and then manually change image source, like
img.Source = new BitmapImage(new Uri("http://...."));
the property changed event would fire.
As for the image appearance, it seems you bind data in wrong way.
Try declarative bindings.
There are several things wrong with this code:-
You've bound directly to the BitmapImage exposed by the BitmapSource property so you've taken your nested Item class out of the picture anyway.
Also for the property setter to be called you would need something to assign a value to the Image elements Source property and your binding would need to be in two way mode.
Your binding object creation is confused, it specifies a path (which is wrong anyway) but then binds direct to source.
Hence your code would need to look like this:-
Binding b = new Binding("BitmapSource");
b.Source = ItemsManager.Instance.GetItem("123");
b.Mode = BindingMode.TwoWay;
Now when a new BitmapImage is assigned the Image Source property your setter code should run. However it should be born in mind that the this property is of the more general type ImageSource. Hence this code will break if another derivative of ImageSource is assigned instead.
One other thing which may be a problem, I can't recall of the top of my head whether Silverlight supports binding to nested types. You might need to bring your Item class out of ItemsManager and give it a more specific name like ManagedItem.
First, do not bind to BitmapImage unless you have a good reason. Binding to a string is good enough. The implicit conversion will happen automatically. Second, use declaritive binding. Programatic creation and binding is a real mess. Third, only implement INotifyPropertyChanged if you need to send changes of that property to the UI.
You are likely over complicating your situation with all this extra code.
Thanks for explanations. However, I don't need a TwoWay binding. Just one way, once ItemsManager downloads Item image, it should be automatically updated in the Image control.
So, I changed my code to this:
ItemsManager.Instance.AddItem("123");
Binding b = new Binding("BitmapSource");
b.Source = ItemsManager.Instance.GetItem("123");
Image img = new Image();
img.SetBinding(Image.SourceProperty, b);
img.Width = (double)100.0;
img.Height = (double)100.0;
LayoutRoot.Children.Add(img);
I also took Item out of ItemsManager scope, so it is now in its own class file, but image still stays empty, even though bitmap image arrives, and changes in BitmapSource property of Item object.

WPF: Data binding with code

How do I use data-binding from code (C# or VB)?
This is what I have so far, but it is displaying Binding.ToString instead of m_Rep.FirstName.
Public ReadOnly Property TabCaption As Object
Get
Return New Label With {.Foreground = Brushes.Black, .Content = New Binding("FirstName"), .DataContext = m_Rep}
End Get
End Property
Yes, binding in code is a little different from straight assignment (which is how XAML makes it look like it works).
I can give you an example in C# - shouldn't be too far removed from VB.NET.
var label = new Label { Foreground = Brushes.Black, DataContext = m_Rep };
label.SetBinding(Label.ContentProperty, new Binding("FirstName"));
return label;
So the "SetBinding" method binds the "FirstName" path (of the DataContext) to the label's Content property.
You should use m_Rep as a Source of Binding
I have some sample C# code for you as below
Person myDataSource = new Person("Joe");
// Name is a property which you want to bind
Binding myBinding = new Binding("Name");
myBinding.Source = myDataSource;
// myText is an instance of TextBlock
myText.SetBinding(TextBlock.TextProperty, myBinding);
Hope to help

Set the background color of DataGridHeaderBackground in Silverlight datagrid

I have a application where user can set the datagrid header background color in runtime. How can I do this? I tried the same through the following code but it is throwing exception.I have used binding and but it's not working.
var style = this.Resources["DataGridHeaderStyle"] as Style;
style.Setters.SetValue(DataGridColumnHeader.BackgroundProperty, "Red");
Without further details (such as the exception you are getting) its difficult to see why you are getting an exception. I suspect that the style variable has a null reference.
I also suspect that the reason its null is that the "DataGridHeaderStyle" doesn't exist in the resource dictionary of the this object, which I would guess is a UserControl. In order to acquire the Style you need to do this look up on the actual FrameworkElement object that holds the Style in its Resources property. (Note programmatic access to the resources does not cascade up the visual tree searching the resource of parents).
However, assuming you can fix that you still have a problem. The use of SetValue on the Setters colleciton itself is nothing like what you actually need to be doing.
You need to be doing this:-
style.Setters.Add(new Setter(DataGridColumnHeader.BackgroundProperty, new SolidColorBrush(Colors.Red));
Of course this only works if the style doesn't already contain an Setter for the property. Hence a more robust version is:-
var setter = style.Setters
.OfType<Setter>()
.Where(s => s.Property == DataGridColumnHeader.BackgroundProperty)
.FirstOrDefault();
if (setter != null)
setter.Value = new SolidColorBrush(Colors.Red);
else
style.Setters.Add(new Setter(DataGridColumnHeader.BackgroundProperty, new SolidColorBrush(Colors.Red));

OneWay binding stops working after the target manually updated

I have such WPF binding code:
TestModel source = new TestModel();
TestModel target = new TestModel();
Bind(source, target, BindingMode.OneWay);
source.Attribute = "1";
AssertAreEqual(target.Attribute, "1");
target.Attribute = "foo";
source.Attribute = "2";
AssertAreEqual(target.Attribute, "2");
The second assertion fails! This seems odd for me.
Also, I tried 'OneWayToSource' instead of 'OneWay', and all works as expected.
Bind(source, target, BindingMode.OneWayToSource);
target.Attribute = "1";
AssertAreEqual(source.Attribute, "1");
source.Attribute = "foo";
target.Attribute = "2";
AssertAreEqual(source.Attribute, "2");
Other details:
void Bind(TestModel source, TestModel target, BindingMode mode)
{
Binding binding = new Binding();
binding.Source = source;
binding.Path = new PropertyPath(TestModel.AttributeProperty);
binding.Mode = mode;
BindingOperations.SetBinding(target, TestModel.AttributeProperty, binding);
}
class TestModel : DependencyObject
{
public static readonly DependencyProperty AttributeProperty =
DependencyProperty.Register("Attribute", typeof(string), typeof(TestModel), new PropertyMetadata(null));
public string Attribute
{
get { return (string)GetValue(AttributeProperty); }
set { SetValue(AttributeProperty, value); }
}
}
What is wrong with my code?
Setting target.Attribute = "foo"; cleared the binding.
MSDN:
Not only do dynamic resources and
bindings operate at the same
precedence as a local value, they
really are a local value, but with a
value that is deferred. One
consequence of this is that if you
have a dynamic resource or binding in
place for a property value, any local
value that you set subsequently
replaces the dynamic binding or
binding entirely. Even if you call
ClearValue to clear the locally set
value, the dynamic resource or binding
will not be restored. In fact, if you
call ClearValue on a property that has
a dynamic resource or binding in place
(with no "literal" local value), they
are cleared by the ClearValue call
too.
Not a binding expert but I believe you are running into a WPF dependency property precedence issues. It's likely that setting the value directly takes precedence over the binding value. That's why it overrides the binding.
Here's a full dependency property listing: http://msdn.microsoft.com/en-us/library/ms743230.aspx
Example: TextProperty is "Text"
dependency property of TextBox.
Calling these in code should be:
TextBox1.TextProperty="value";
WPF properties can be set two ways:
by invoking DependencyObject.SetValue method (eg. instance.SetValue(TextProperty,"some text"))
or
using CLR Wrapper (eg. instance.Text="some text").
TextBox.TextProperty is a static DependencyProperty object, so you can't assign a string value to a reference type.
If you set Binding Mode to OneWay, this means that the binding works only in one way: the target is updated when the source change.
But the target must be a dependency property, and the code you have is a CLR .NET property. You should set the value on the the target using the registered dependency property name, not just an ordinary .NET property name. The Jared's answer is quite right, this might bring confusion in resolving conflict between WPF dependency property and ordinary .NET CLR property.
If you follow the convention, the dependency property should be in the form of "propertyname"+property.
Example: TextProperty is "Text" dependency property of TextBox. Calling these in code should be:
TextBox1.TextProperty="value";
For more information on setting the source of Binding:
http://msdn.microsoft.com/en-us/library/ms743643.aspx

Resources