I have a databound TextBlock control (which is being used inside a DataTemplate to display items in a ListBox) and I want to make all the text in the control bold. I can't seem to find a property in the properties explorer to set the whole text to bold, and all I can find online is the use of the <Bold> tag inside the TextBlock, but I can't put that in as the data is coming directly from the data source.
There must be a way to do this - but how? I'm very inexperienced in WPF so I don't really know where to look.
Am I missing something, or do you just need to set the FontWeight property to "Bold"?
<TextBlock FontWeight="Bold" Text="{Binding Foo}" />
Rather than just having a TextBlock, try this:
<TextBlock>
<Bold>
<Run />
</Bold>
</TextBlock>
Then databind to the Run.TextProperty instead.
You say that the data is coming directly from the datasource; is it possible to place a layer of abstraction in front of it? Its quite common to create a View for what you are displaying, and have the View communicate with the data. The most common implementation of this idea is Model View View-Model (MVVM). Have a read about it online.
You might have a 'DisplayText' property that is bound to the textbox, and it is simply a 'getter' that wraps the underlying text. It can detect if the text is already wrapped in and if not, wrap it.
Eg.
public class TestView {
private Test datasource;
public TestView(Test source)
{
this.datasource = source;
}
public string DisplayText {
get {
if (datasource.Text.Contains("<bold>")==false) {
return "<bold>" + datasource.Text + "</bold>";
}
return datasource.Text;
}
}
}
Then, bind to the View instead of directly to the object.
Related
If it helps to know, I'm using Caliburn.Micro, and have laid out everything based on the MVVM framework requirements as I understand them.
Here is the relevant XAML ...
<ListView ItemsSource="{Binding ProductListBox}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding ProductID}"/>
<TextBlock Text="{Binding ProductDescription}"/>
<TextBlock Text="{Binding ProductDescriptionExtended}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The above content of the ListView is created dynamically based on the content of ProductListBox, which sits inside this class...
public class MainViewModel : Screen
{
public List<ProductModel> ProductListBox { get; private set; }
public void GetProductsButton()
{
DBAccess db = new DBAccess();
ProductListBox = db.GetProducts(SearchTextBox);
NotifyOfPropertyChange(() => ProductListBox);
}
}
That List is populated when a Button is clicked, it causes the above GetProductsButton() method to start.
Over in the DBAccess class, in the GetProducts method I would like to change the format of the text in the ProductListBox<>.ProductDescription. Its a string, but I'm happy to change it to any type should it help the cause!
The kind of change I would like to achieve is simply (highlighting) changing the background color of selected text based on found search terms the user had typed in, that the bound XAML TextBlock will then display.
What I cant work out is how to highlight any text at this time via C#, that will then be displayed purely by the bound XAML control... I've only been able to do it by hardcoding XAML which is not going to help for what I'm trying to achieve.
In the DBAccess class and inside the GetPeoducts method, this is the kind of thing I have tried in order to make this happen...
I've pasted in this code...
TextBlock textBlock1 = new TextBlock();
textBlock1.Inlines.Add(new Bold(new Run("TextBlock")));
textBlock1.Inlines.Add(new Run(" is designed to be "));
textBlock1.Inlines.Add(new Italic(new Run("lightweight")));
textBlock1.Inlines.Add(new Run(", and is geared specifically at integrating "));
textBlock1.Inlines.Add(new Italic(new Run("small")));
textBlock1.Inlines.Add(new Run(" portions of flow content into a UI."));
Which although doesn't change background color, will lead to that if I could make it work ;)
I think in every example of the kind of code I've quoted above, the writer always ends that code with something like this...
this.Content = textBlock1;
And the examples I've seen also always seem to inherit from the Window class. I don't want to do it this way. I want to find my search terms, highlight the given text and allow the bound TextBlock to update itself based on the populated List of type ProductModel.
I've tried changing the type of ProductDescription to a TextBlock, and used the above code to allow my XAML to remain bound directly to it
ie..
PM.ProductDescription = textBlock1;
In this case there was no GUI output at all for the content.
I've also tried straight HTML-like formatting to the string type
ie..
PM.ProductDescription = "<bold>Hello World</bold>";
This gives the literal text output of <bold>Hello World</bold> on the TextBlock control though.
I've also tried changing the type of Binding key from Text to other things in the hope I might work it out, without success.
Any ideas or help would be greatly appreciated, thank you!
Here is a little picture of what I would like to see the program be able to do..
Hi I am using wpf mvvm approach in my app.
I am getting this error:-
Specified element is already the logical child of another element. Disconnect it first. WPF
I have written code like this:-
In my xaml page :
<Border Background="White" BorderThickness="0" x:Name="bdrPdf">
<ContentControl x:Name="CntControlPdf"
MouseDown="Img_MouseDownPdf"
MouseMove="Img_MouseMovePdf"
MouseUp="Img_MouseUpPdf"
Width = "{Binding Path=ViewPageWidth}"
Height = "{Binding Path=ViewPageHeight}"
Content="{Binding Path=PDFViewWPFSource,ElementName=root}" >
</ContentControl>
</Border>
In Code behind :-
public pdftron.PDF.PDFViewWPF PDFViewWPFSource
{
get { return (pdftron.PDF.PDFViewWPF)GetValue(ImgSourcePropertyPDF); }
set { SetValue(ImgSourcePropertyPDF, value); }
}
// Using a DependencyProperty as the backing store for PDFViewWPFSource. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ImgSourcePropertyPDF =
DependencyProperty.Register("PDFViewWPFSource", typeof(pdftron.PDF.PDFViewWPF), typeof(PageView), new UIPropertyMetadata(default(pdftron.PDF.PDFViewWPF)));
I am behindinf PDFtron control dynamically.
How can I solve this problem.
Where I have to written the code to de-attach this element.
Your error simply means that in WPF, you cannot display the same UI element more than once at the same time. You have two choices... either you can remove one from the UI before adding it somewhere else, or you can fake it.
What I mean by faking it, is that you can recreate the UI element elsewhere, not actually duplicating the control. You can do that either by creating a new element of the same type to use instead, or you could display your UI element via a DataTemplate and ContentControl. Then you could just provide WPF with a new object of the same type with the same values and WPF will render it in the same way as the first, making it appear as if you had duplicated it.
UPDATE >>>
thnks Sheridan, but I have to bind the ui element Like a data binding. How can I do this?I have add multiple control at runtime
In WPF, we don't data bind UI elements. Instead, we declare a data object (class) that contains the data for the element and then define a DataTemplate that will render the UI element. We then use the type of the data object as the data bound property. Take this simple example:
<DataTemplate DataType="{x:Type YourLocalPrefix:YourDataType}">
<YourUiPrefix:PDFViewWPF DataContext="{Binding}" />
</DataTemplate>
Then your property should look like this:
public YourDataType PDFViewWPFSource
{
get { return (YourDataType)GetValue(ImgSourcePropertyPDF); }
set { SetValue(ImgSourcePropertyPDF, value); }
}
Finally, display your UI element in a ContentControl:
<ContentControl Content="{Binding PDFViewWPFSource}" />
The WPF framework will see the object of type YourDataType, find the relevant DataTemplate and render your control in place of the ContentControl.
In my MVVM test project I want to bind my textbox to the object from viewmodel:
public class ContactViewModel : BaseNotifyPropertyChanged
{
Contact _selectedItem;
public ContactViewModel()
{
ContactModel contactModel = new ContactModel();
_selectedItem = contactModel.ContactList[1]; // this contains first contact from the list;
}
}
public Contact SelectedContact
{
get
{
return _selectedItem;
}
}
in my Contact class I am overriding ToString Method in order to show first Contact's first name:
public override string ToString()
{
return _firstName.ToString();
}
And here is my XAML binding:
<TextBox Height="23" HorizontalAlignment="Left" Name="SelectedItemTextBox" Text="{Binding Path=SelectedContact}" VerticalAlignment="Top" Width="120" />
And for some reason this textbox is always empty. However, if I change
public String SelectedContact
{
get
{
return _selectedItem.LastName;
}
}
it works perfectly.
Stanislav, you did a mistake in other place. You try to bind to object, binding doesn't know what to show and apply ToString() to your Contact object. If you overrode ToString(), it had to show a returned value of this method. I created the test app, and it works in this way!
What I can see in your code, in ToString() you return FirstName, but in changed SelectedContact it is SecondName - did you fill first name before?
You wrote in comment that tried to access to first element, but in code you take second element of ContactList
Moreover, use binding in this way is incorrect. If you want to access to LastName use next way:
<TextBox Text="{Binding Path=SelectedContact.LastName, Mode=OneTime}" />
And remove ToString() overriding.
EDIT: Unlike to other controls where binding is OneWay by default in TextBox it is TwoWay by default. It was done because native behavior of TextBox is show and edit value (not only show as in other controls). Moreover if you don't plan to change value (you don't plan, because ContactModel doesn't implement INotifyPropertyChanged) it is recommended to use OneTime mode (for performance).
TwoWay has some restriction - you can't use it for read-only property (SelectedContact is read-only in your code). Because binding can't change the value in this case - make sense. It is strange that app lunched in your case and TextBox was empty, because in my case I get the error "A TwoWay or OneWayToSource binding cannot work on the read-only property 'SelectedContact' of type 'WpfApplication1.ContactViewModel'." until I changed binding mode in TextBox.
I guess you followed this Article on MSDN:
http://msdn.microsoft.com/en-us/library/ms742521%28v=vs.110%29.aspx
Alltough the article says, that the standard representation of a ListBox is a List of ToString representation of its contents, this is not the case for every other element.
I would highly recommend to create a DataBinding Template for you Contact class, it's a much cleaner way to implement this behaviour than overriding ToString.
Ah, found it, I just had to change my TextBox to the TextBlock and now everything works properly !
It seems like TextBlock does understand how to show objects, but TextBox doesn't.
I have a custom component that is basically a text box with an attached button. The button is supposed to perform an action on the text box; for example clicking the button could fill the text box with some random string.
The text fields are bound to properties in the ViewModel. It basically looks like this:
What would be the best way to set up a commanding that is general to the component?
What I did so far is that I have a single general RelayCommand in my ViewModel that expects a parameter. Each button has its command set to that single command and I use the CommandParameter property to add some information about which text field component I am actually talking about. The ViewModel then uses that information to find out the correct property and change its value (updating the text boxes via binding).
While this works fine, I dislike that I have to manually insert the information about the related text box or context. Ideally, I would like to have the command executed within a context-scope that already knows which text box or bound property it is talking about. Is there some way to do this?
Another problem I have run into is that I want to bind the button action to a key command. So when I’m focussing a text box and press a key shortcut, I want it to behave as if I have clicked the correct button, i.e. execute the command and pass the correct context information. My alternative would be to put this into the code-behind and basically extract the command parameter from the current focus, but I’d prefer a cleaner solution.
Is there any good way to make this work with MVVM?
How about something along these lines:
public class TextBoxAndCommandPresenter : INotifyPropertyChanged
{
private readonly Action<TextBoxAndCommandPresenter> _action;
public TextBoxAndCommandPresenter(string description,
Action<TextBoxAndCommandPresenter> action)
{
Description = description;
_action = action;
}
public string Description { get; private set; }
public string Value { get; set; }
public ICommand Command
{
get { return new DelegateCommand(() => _action(this)); }
}
}
Used like this:
var presenter = new TextBoxAndCommandPresenter("Field 1",
p => p.Value = "hello world");
With XAML:
<UserControl ...>
<UserControl.Resources>
<DataTemplate DataType="{x:Type TextBoxAndCommandPresenter}">
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Description}"/>
<TextBox Text="{Binding Value}"/>
<Button Command="{Binding Command}">Click</Button>
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<ContentPresenter Content="{Binding}"/>
</UserControl>
As I already had a custom control for the text box and the button combination, creating a UserControl wasn’t really a necessary option for me. My control exposes bindable properties for the button’s command and command parameter, and for now, I’m sticking with what I have explained in the question; using the command parameter to update the corresponding property in the view model that is then updated via data binding.
Depending on how repetitive it will become later, I might encapsulate that in either multiple custom controls or build a similar helper as Scroog1 showed.
As for the key command, which was actually my primary concern, I realized that this is ultimately something the view alone should handle. So my view model is completely oblivious of the key command.
I know have a standard command binding to the window’s code-behind that looks up the currently focused element, checks if it is of the type of my custom control and then simply executes the underlying command. So the code-behind is essentially just delegating the command execution to the focused control.
While this is not a perfect solution, as I’d rather have some actual “context sensitivity” for commands, this is working fine for now and still separates the view from the logic correctly.
i have a datatemplate declared in xaml.
for e.g.
<DataTemplate x:Key="TestTemplate">
<StackPanel>
<TextBox Name="txtBox" Visibility="Visible"></TextBox>
</StackPanel>
</DataTemplate>
I wish to set the binding for txtBox in code behind before the element is generated because i have different binding paths for different elements that get generated
I can get the template in the code behind as :
DataTemplate tmplt = FindResource("TestTemplate") as DataTemplate;
but i am not sure what to do next. How to get the the txtBox reference to set the binding.
We have to remember one thing that Templates are not instantiated UI controls. They are streamed obejcts in XAML and are shared between UI elements. So if you edit a dataTemplate and change its stucture (by adding, editing, deleting an element under the template) it would change the one data template which is shared among controls. Thus other elements using that template will also be affected by the change.
Now lets address your issue of adding a dynamic biding to a textbox. You say each generated textbox will have different binding paths. So this definitely does NOT call for changing the data template itself!
You will have to access the text box and add dynamic bindings to it AFTER the textbox's is generated.
I see that your binding differs based on your "situation", so why cant you use TemplateSelector? Template selector will decide which data template (having one specific binding applied to the TetxBox) at runtime.
The first part of answer - is FindName() method.
example:
DataTemplate tmplt = FindResource("TestTemplate") as DataTemplate;
TextBox my = (TextBox)tmplt.FindName("txtBox");
try out this, it should help to get access to TextBox control. I think that you know how to bind to. If you want your DataBinding behave different way, use MultiBinding and Converter.
EDIT
public class GeneralObject
{
private object someObject;
public GeneralObject(object initObject)
{
this.someObject = initObject;
}
//If you want to bind to some text, for example
public string Text
{
get
{
//I think you know which objects are coming as input
if (this.someObject is SpecialClass1)
return ((SpecialClass1)this.someObject).SpecialClass1TextProperty;
if (this.someObject is SpecialClass2)
return ((SpecialClass2)this.someObject).SpecialClass2TextProperty;
//and so on.
}
}
}
EDIT 2
One more possible way
So I remember, that WPF have ContentControl!
<ContentControl Content="{Binding Path=CurrentObject}"/>
But in this case you have to create number of DataTemplate's, every Template for one class.
<DataTemplate DataType="{x:Type local:SpecialClass1}">
...
</DataTemplate>
<DataTemplate DataType="{x:Type local:SpecialClass2}">
...
</DataTemplate>
<!--and so on-->
WPF resolve DataTypes of ContentControl.Content property, and put to the ContentControl right DataTemplate.