I have a note application with a ListBox control, which lists all the available notes from the ObservableCollection<Note> Notes. class Note has attributes like
String Title;
bool Has_Reminder;
DateTime Reminder_Date;
What I want is that the TextBlock element, which shows the Reminder_Date, is only shown, if Has_Reminder is true. But I do not know how to access this attribute from my custom control NoteListItem. Its this.DataContext attribute is null, but the control still properly displays the Note's bound attributes handed down by the ListBox ItemsSource. How can I achieve that?
Thanks for your help.
I tried to read the attributes in the constructor, which did not work:
public NoteListItem()
{
InitializeComponent();
Note this_note = LayoutRoot.DataContext as Note; // turns out, this_note is null
if (!this_note.Has_Reminder)
Reminder_Info.Visibility = System.Windows.Visibility.Collapsed;
}
NoteListItem control
<Grid x:Name="LayoutRoot" >
<TextBlock x:Name="Title" Text="{Binding Title}" />
<TextBlock x:Name="Reminder_Date" Text="{Binding Reminder_Date}" />
</Grid>
NoteList control:
<ListBox x:Name="NoteListBox" ItemsSource="{Binding Notes}" >
<ListBox.ItemTemplate>
<DataTemplate>
<local:NoteListItem />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Do you know how to use a converter? Your converter would convert a bool to a Visibility, then you can bind the TextBlock's Visibility to Has_Reminder:
<TextBlock x:Name="Reminder_Date" Text="{Binding Reminder_Date}" Visibility="{Binding Has_Reminder, Converter={...}}"/>
This might help: http://www.jeff.wilcox.name/2008/07/visibility-type-converter/
Related
I have a User control and I bind the tooltip of that control into some object's property
<usercontrols:ucButton x:Name="xSaveCurrentBtn" ButtonType="ImageButton" ButtonFontImageSize="16" ButtonImageWidth="18" ButtonImageHeight="18" ButtonImageType="Save" Click="xSaveSelectedButton_Click" ButtonStyle="{StaticResource $ImageButtonStyle_Menu}" DockPanel.Dock="Right" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,0,0">
<usercontrols:ucButton.ToolTip>
<ToolTip Content="{Binding ItemName, Mode=OneWay}" ContentStringFormat="Save {0}"/>
</usercontrols:ucButton.ToolTip>
</usercontrols:ucButton>
from the code I set the data context of the ucButton to be my object:
xSaveCurrentBtn.DataContext = WorkSpace.Instance.CurrentSelectedItem;
sometimes the CurrentSelectedItem is null, and if this is the case I want the tooltip to display "No Item Selected"
I tried doing this:
xSaveCurrentBtn.Tooltip = "No Item Selected";
but when the CurrentSelectedItem isn't null and I reset the xSaveBtn.DataContext to that object, I am still seeing the No Item Selected tooltip as if my WPF tooltip section was overriden and its no longer binding into the datacontext ItemName Property
You are trying to set a property to two values at the same time. It's impossible.
What you are doing in XAML is equivalent to:
xSaveCurrentBtn.Tooltip = new ToolTip() {.....};
When you setting a string value to the same property, the previous value is lost. And it is not possible to restore it if you do not save it first.
You might want to assign a value in case of a binding error:
<ToolTip Content="{Binding ItemName,
Mode=OneWay,
FallbackValue='No Item Selected'}"
ContentStringFormat="Save {0}"/>
how can I bind the data context to update to be the new CurrentSelectedItem without explicitly setting it?
Assuming that «WorkSpace.Instance» is an immutable property that returns an instance of «WorkSpace» and «CurrentSelectedItem» is a property with an «INotifyPropertyChanged.PropertyChanged» notification, then you can do this:
<usercontrols:ucButton DataContext="{Binding CurrentSelectedItem, Source={x:Static viewmodels:WorkSpace.Instance}}" ...>
The «viewmodels» prefix depends on the assembly and namespace in which the «WorkSpace» class is declared.
you can use ContentTemplate with TextBlock, which will either use StringFormat, or TargetNullValue depending on ItemName being null:
<usercontrols:ucButton.ToolTip>
<ToolTip Content="{Binding ItemName}">
<ToolTip.ContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding StringFormat='Save {0}',
TargetNullValue='No Item Selected'}"/>
</DataTemplate>
</ToolTip.ContentTemplate>
</ToolTip>
</usercontrols:ucButton.ToolTip>
or if you bind Tooltip.Content differently:
<usercontrols:ucButton.ToolTip>
<ToolTip Content="{Binding}">
<ToolTip.ContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=ItemName,
StringFormat='Save {0}',
FallbackValue='No Item Selected'}"/>
</DataTemplate>
</ToolTip.ContentTemplate>
</ToolTip>
</usercontrols:ucButton.ToolTip>
I'm developing a WPF app using MVVM pattern with Caliburn.Micro
I have a config file that contains positions of where XAML elements should be inside of a StackPanel
# in this case RU_ELEMENT should be at the top, EN_ELEMENT second and DE_ELEMENT last
EN_ELEMENT = 1
DE_ELEMENT = 2
RU_ELEMENT = 0
This seems to be pretty basic yet I'm unable to find a way to do this. I found this thread: change the children index of stackpanel in wpf but changing it this way seems to be too complicated for what I am after. I just need to set an index of an element from a variable. I feel like there should be a much simpler way. I'm also ok with using some other, perhaps more appropriate layout panel than StackPanel.
XAML:
<!-- Language1 -->
<TextBlock Text="English" Foreground="DarkGray" FontSize="16"/>
<TextBox
VerticalAlignment="Top"
Height="150"
Text="{Binding SelectedItem.ValueEN, UpdateSourceTrigger=PropertyChanged}"
cm:Message.Attach="[Event GotFocus] = [Action FocusedTextBox('english')]" />
<!-- Language2 -->
<TextBlock Text="German" Foreground="DarkGray" FontSize="16"/>
<TextBox
VerticalAlignment="Top"
Height="150"
Text="{Binding SelectedItem.ValueDE, UpdateSourceTrigger=PropertyChanged}"
cm:Message.Attach="[Event GotFocus] = [Action FocusedTextBox('german')]" />
On a side note: I find WPF and C# in general to have much less discussions and "how to" guides than all of my previous languages (Java, Python, JS) so researching things online is usually a dead end for me. I'm not sure to why that is since C# is a very popular language but I'm really struggling with finding help online.
A solution could be to use an ItemsControl that would host the xaml elements. You can bind the items like <ItemsControl ItemsSource="{Binding ListOfItems} ...
Then you could easily sort the items in the corresponding ViewModel. Like so:
public BindableCollection<YourElement> ListOfItems {get;set;}
...
ListOfItems.Sort()
Note that YourElement class should have a comparator.
EDIT: As per request I'll explain it more detailed:
In your Xaml you have to declare a ItemsControl like so:
<ItemsControl ItemsSource="{Binding ListOfItems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Language}" Foreground="DarkGray" FontSize="16"/>
<TextBox
VerticalAlignment="Top"
Height="150"
Text="{Binding TextValue, UpdateSourceTrigger=PropertyChanged}"
cm:Message.Attach="[Event GotFocus] = [Action FocusedTextBox($this)]" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
And in your backend you should first create a class that's going to represent your item in the ItemsControl. For example:
public Class MyItem{
public string Language {get;set;}
public string TextValue {get;set;}
}
Finally in your ViewModel you'll need to create the list of items that you bind with the ItemsControl like so:
public BindableCollection<MyItem> ListOfItems {get;set;}= new BindableCollection<MyItem>();
//here you can add them in the order that is specified by the config file
public void LoadItems(){
ListOfItems.Add(new MyItem{Language="English"});
ListOfItems.Add(new MyItem{Language="Russian"});
ListOfItems.Add(new MyItem{Language="German"});
}
public void FocusedTextBox(MyItem item){
//do here whatever you want
}
Hello Guys I hope yall doing great!
I have a problem with a datagrid, I want to put this in datagrid cell for example : "/100" which '100' is the quantity in stock in my database using entity framework, I want to do this so the user tap how many items he wants in a textbox besides the label/textBlock like this :
DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBox materialDesign:HintAssist.Hint="0"/>
<TextBlock Text="{Binding ElementName=productQuantityStock}" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
I hope you guys understand what I want to do, and please mind my bad English
In the code-behind you'll need to bind a context. The context will need a property and a field so the the value can be updated. You should also make use of a method that notifies the view that the property has been updated.
The code behind will look something like this.
public class DataContextOfView
{
private int _productQuantityStock;
// Because you'll be working with values of type int you should make it an int
public int ProductQuantityStock
{
get { return _productQuantityStock;}
set { if(_productQuantityStock != value)
{
_productQuantityStock = value
// notify that the value of the property has changed.
OnPropertyChanged(nameof(ProductQuantityStock));
}
}
}
}
The code in the view should have a reference to the property
DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBox materialDesign:HintAssist.Hint="0"/>
<TextBlock Text="{Binding ProductQuantityStock, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
Hej
I want to create a standard holdevent. When you hold an element, there would appear some options you could chose like a new list.
How do you create this, is it just simply done with a popup or is there a smarter way?
Extra
After finding the answer, see answer below, some nice info is:
Put the context creation inside the hold event.
Then you can change to different contextmenus depending on the item. You can get the item that was holded by the following
private void StackPanel_Hold(object sender, GestureEventArgs e)
{
ItemViewModel itemViewModel = (sender as StackPanel).DataContext as ItemViewModel;
string t = itemViewModel.LineOne;
}
And
<ListBox x:Name="MainListBox" Margin="0,0,-12,0" ItemsSource="{Binding Items}" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Height="78" Hold="StackPanel_Hold">
<TextBlock Text="{Binding LineOne}" />
<TextBlock Text="{Binding LineTwo}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
A good link for easy implementation is also youtube link below, replicated here :
Youtube
A ContextMenu is one option..
http://blogs.msdn.com/b/msgulfcommunity/archive/2013/05/19/windows-phone-toolkit-context-menu-getting-selected-item-within-a-long-list-selector.aspx
List box is not binded just a Combobox replacement (values are exposed)
Xaml
<ListBox SelectionChanged="LBX_AddTaskOptions_SelectionChanged" HorizontalAlignment="Left" Margin="19,29,0,0" Name="LBX_AddTaskOptions" VerticalAlignment="Top" Width="125" FontWeight="Bold" Background="Beige">
<ListBoxItem Background="Beige" FontWeight="Bold" v>
<StackPanel Orientation="Horizontal">
<TextBlock Text="internet"></TextBlock>
<Image Source="Images\IE_BlackRed.png" Height="30"></Image>
</StackPanel>
</ListBoxItem>
<ListBoxItem Background="Beige" FontWeight="Bold">
<StackPanel Orientation="Horizontal">
<TextBlock Text="localFolder"></TextBlock>
<Image Source="Images\Folder_Black.png" Height="30"></Image>
</StackPanel>
</ListBoxItem>
</ListBox>
CodeBehind
private void LBX_AddTaskOptions_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var SelItm = LBX_AddTaskOptions.SelectedItem.ToString();
MessageBox.Show(Sel);
}
i have searched for that question, though answers are only for complex issues
as i am fresh .net Developer, i know all methods to extract DDL text/value
i even made extentions , though couldn't figure how to do this simple value extraction
shouldn't it be simple ?
messageBox shows the name of control (:
This isn't quite the right approach for XAML. You don't want to list out the markup for each item -- instead, use an ItemTemplate to define how it should look, and use bindings to render the actual item:
<ListBox SelectionChanged="LBX_AddTaskOptions_SelectionChanged" Name="LBX_AddTaskOptions">
<ListBox.ItemTemplate>
<ListBoxItem Background="Beige" FontWeight="Bold" v>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" />
<Image Source="Images\IE_BlackRed.png" Height="30" />
</StackPanel>
</ListBoxItem>
</ListBox.ItemTemplate>
</ListBox>
Bind the ListBox ItemsSource to the model data itself (ie, the array of strings in this case). Now, eventually you'll probably want to use a view model, but you can also add the items from code behind on load:
string[] ListBoxItems = new string[] { "internet", "local folder" };
LBX_AddTaskOptions.ItemsSource = ListBoxItems;
This should result in SelectedValue giving you the correct value.
Footnote -- you could get the selected value using the markup you've written out in the question -- but it would be ugly and would defeat the whole purpose of XAML. You'd need to cast SelectedItem to a ListBoxItem, then get its child and cast that to a StackPanel, get its children, etc, you get the idea. And then, of course, if the markup changes at all, the code you just wrote is no longer valid.
The item that you are getting in your selected value is a ListBoxItem with a control inside it. If you want to extract the value like the text then you have to do this
private void LBX_AddTaskOptions_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var SelItm = LBX_AddTaskOptions.SelectedItem as ListBoxItem;
var StackPanel = SelItm.Content as StackPanel;
foreach (var child in StackPanel.Children)
{
if(child is TextBlock)
{
MessageBox.Show((child as TextBlock).Text);
}
}
}
You have to sort of dig into the control to get the actual text. There are a lot of ways to get the value but this is the pretty basic one.
Calling ToString() method will just convert the current object as a string which is a ListBoxItem.