Single-line wpf textbox horizontal scroll to end - c#

I have a templated listbox which template among other things contains a wpf textbox too. The data is provided to the listbox through ItemsSource.
The textboxes display filepaths and these are usally quite long. I want when the textboxes are loaded to show the end of the filepaths.
I tried a combination of DataContextChanged event and setting HorizontalScrollBarVisibility (using double.max or getting the real char length) but to no success. The DataContextChanged seems to be the correct event to use as it fires on each setting of the ItemsSource.
Edit:
Here is sample code to show when the suggestion by Lester works and when it doesnt. I am trying to have it work when the text is set through binding.
<Window x:Class="WpfAppTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
Loaded="LoadedHandler">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<TextBox Name="tbb" Width="50" Height="20" Text="{Binding Path=Str}"
IsReadOnly="True" Grid.Column="0" Grid.Row="0"
DataContextChanged="ContextChangedHandler"/>
<ListBox SelectionMode="Single" x:Name="listBox" Grid.Column="0" Grid.Row="1"
VerticalAlignment="Top">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Width="50" Height="20" Text="{Binding Path=Str}"
IsReadOnly="True"
DataContextChanged="ContextChangedHandler"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var obj = new SomeClass
{
Str = "qwetyuiuropqo[psdal;dkas;ldamzxn m,cnz128391"
};
listBox.ItemsSource = new List<SomeClass> { obj };
tbb.DataContext = obj;
}
public class SomeClass
{
public string Str { get; set; }
}
private void LoadedHandler(object sender, RoutedEventArgs e)
{
var obj = new SomeClass
{
Str = "qwetyuiuropqo[psdal;dkas;ldamzxn m,cnz128391"
};
listBox.ItemsSource = new List<SomeClass> { obj };
tbb.DataContext = obj;
}
private void ContextChangedHandler(object sender, DependencyPropertyChangedEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null) return;
textBox.CaretIndex = textBox.Text.Length;
var rect = textBox.GetRectFromCharacterIndex(textBox.CaretIndex);
textBox.ScrollToHorizontalOffset(rect.Right);
}
}

This code worked for me for scrolling to the end of the TextBox (taken from this question):
textBox.CaretIndex = textBox.Text.Length;
var rect = textBox.GetRectFromCharacterIndex(textBox.CaretIndex);
textBox.ScrollToHorizontalOffset(rect.Right);

Solution is to change DataContextChanged event with Loaded so that proper notifications are received for the textbox.

Related

C# XAML UWP - MenuFlyoutItem List not updating consistently in MenuFlyoutSubItem

this is probably a simple solution - its just a bit long to explain.
I add custom list view items to a ListView at run-time. Each ListView item has a Name, a Bool and a button. The button when clicked displays a Flyout menu which has subitem menu as shown in the image. The subitem menu should only display the name of all other items not itself. The correct behavior is shown in the first image as the "Item 4" menu button was clicked we only see Items 0 to 3 listed in the submenu.
The issue is that if i navigate to a submenu and then later add new items to the listbox, the new items never appear in the submenu for the older items previously navigated to. Like in the image below, where i clicked Item 1 button but only Item 0 and Item 2 are listed and for some reason Items 3 and 4 are not.
Firstly there is a complete minimum VS2019 solution demonstrating the behavior i'm describing above on GitHub here, though i have summarised what i think are the key bits of code below.
Non-boiler plate XAML header (MainPage.Xaml)
xmlns:local="using:DynamicFlyoutMenuTest.ViewModels"
The main ListView defintion and its DataTemplate as well as a button to add ListView items at run-time:
<StackPanel>
<Button Name="AddCustomListItemBtn" Click="AddCustomListItemBtn_Click">Add Custom ListItem</Button>
<ListView
Name="LayerListBox"
Height="Auto"
BorderBrush="{ThemeResource SystemBaseLowColor}"
BorderThickness="1.0"
ItemsSource="{x:Bind ViewModel.MyCustomListItems}">
<ListView.HeaderTemplate>
<DataTemplate>
<Grid Padding="2" Background="{ThemeResource SystemBaseLowColor}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="190" />
<ColumnDefinition Width="132" />
</Grid.ColumnDefinitions>
<TextBlock Style="{ThemeResource CaptionTextBlockStyle}" Text="Name" />
<TextBlock
Grid.Column="1"
Style="{ThemeResource CaptionTextBlockStyle}"
Text="Active" />
</Grid>
</DataTemplate>
</ListView.HeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate x:Name="TableDataTemplate" x:DataType="local:MyCustomListItem">
<Grid Height="48" AutomationProperties.Name="{x:Bind ItemName}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="190" />
<ColumnDefinition Width="132" />
<ColumnDefinition Width="132" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="0"
Padding="10"
VerticalAlignment="Center"
Text="{x:Bind ItemName, Mode=OneWay}" />
<CheckBox
Grid.Column="1"
VerticalAlignment="Center"
IsChecked="{x:Bind isEditing, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<Button
Name="exportLayerButton"
Grid.Column="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Center">
<Button.Flyout>
<MenuFlyout Opening="MenuFlyout_Opening">
<MenuFlyoutItem
Name="Action1Btn"
Click="Action1Btn_Click"
Text="Action 1" />
<MenuFlyoutItem
Name="Action2Btn"
Click="Action2Btn_Click"
Text="Action 2" />
<MenuFlyoutSubItem x:Name="SubActionsBtn" Text="Choose Sub Action">
<MenuFlyoutItem Name="NoSubActionBtn" Text="None" />
</MenuFlyoutSubItem>
</MenuFlyout>
</Button.Flyout>
<Polygon
Fill="Black"
Points="0,0 6,4,0,8"
Stroke="Black" />
</Button>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
MainPage.xaml.cs - Add Item to List and Update Flyout Sub Menu Items
private void MenuFlyout_Opening(object sender, object e)
{
//make MenuFlyoutSubItem list all Items in ListView except the one triggering this function
var menuFlyout = sender as MenuFlyout;
// get the menu list we want to add to
MenuFlyoutSubItem menuSubItems = menuFlyout.Items.Where(x => x.Name == "SubActionsBtn").FirstOrDefault() as MenuFlyoutSubItem;
// get the active maplayerlistitem (that triggered this menu opening event)
MyCustomListItem myCustomListItem = (menuFlyout.Target as Button).DataContext as MyCustomListItem;
menuSubItems.Items.Clear();
foreach (var targetItem in ViewModel.MyCustomListItems)
{
if (myCustomListItem.ItemName != targetItem.ItemName)
{
var tItem = new MenuFlyoutItem();
tItem.Text = targetItem.ItemName.ToString();
//tItem.Click += new Windows.UI.Xaml.RoutedEventHandler(DoSomethingBtn_Click);
menuSubItems.Items.Add(tItem);
}
}
}
private void AddCustomListItemBtn_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
// Update ListView
var newItem = new MyCustomListItem();
newItem.ItemName = "Item " + ViewModel.MyCustomListItems.Count.ToString();
newItem.isEditing = false;
ViewModel.MyCustomListItems.Add(newItem);
}
MainViewModel.cs
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using Microsoft.Toolkit.Mvvm.ComponentModel;
namespace DynamicFlyoutMenuTest.ViewModels
{
public class MainViewModel : ObservableObject
{
public ObservableCollection<MyCustomListItem> MyCustomListItems = new ObservableCollection<MyCustomListItem>();
public MainViewModel()
{
}
}
public class MyCustomListItem : INotifyPropertyChanged
{
public MyCustomListItem()
{
}
private bool _isEditing;
public bool isEditing
{
get { return _isEditing; }
set
{
_isEditing = value;
NotifyPropertyChanged(this, "isEditing");
}
}
private string _itemName;
public string ItemName
{
get { return _itemName; }
set
{
_itemName = value;
NotifyPropertyChanged(this, "ItemName");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void NotifyPropertyChanged(object sender, string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(sender, e);
}
}
}
}
EDIT
You can view the issue in video at https://www.youtube.com/watch?v=yPNNtsS-n5Q
You can reproduce the issue from the GitHub source by
adding 3 items to the ListView using the "Add..." button.
Navigating to the submenuFlyout of each ListViewItem
Add 2 more Listview Items using the "Add..." button
navigate to the submenuFlyout of the two new items and finally
navigate to submenuFlyout of the original 3 items and see that they haven't updated to reflect the additional ListView items added.
I found a workaround by removing the exsiting MenuFlyoutSubItem and adding a new one each time the Flyout is opened. So it's not ideal, but it does work.
If anyone has as an actual solution, id be happy to mark it as such.
Otherwise here is the workaround:
private void MenuFlyout_Opening(object sender, object e)
{
//make MenuFlyoutSubItem list all Items in ListView except the one triggering this function
var menuFlyout = sender as MenuFlyout;
// get the menu list we want to add to
MenuFlyoutSubItem menuSubItems = menuFlyout.Items.Where(x => x.Name == "SubActionsBtn").FirstOrDefault() as MenuFlyoutSubItem;
// get the active maplayerlistitem (that triggered this menu opening event)
MyCustomListItem myCustomListItem = (menuFlyout.Target as Button).DataContext as MyCustomListItem;
menuFlyout.Items.Remove(menuSubItems);
menuSubItems = new MenuFlyoutSubItem();
menuSubItems.Name = "SubActionsBtn";
menuSubItems.Text = "Choose Sub Action";
foreach (var targetItem in ViewModel.MyCustomListItems)
{
if (myCustomListItem.ItemName != targetItem.ItemName)
{
var tItem = new MenuFlyoutItem();
tItem.Text = targetItem.ItemName.ToString();
//tItem.Click += new Windows.UI.Xaml.RoutedEventHandler(DoSomethingBtn_Click);
menuSubItems.Items.Add(tItem);
}
}
menuFlyout.Items.Add(menuSubItems);
}

DependencyPropertyDescriptor help required

I have a simple WPF app, where I have a combobox and a label, using dependency property I want to show the selected Item in label, when user select any item in the combobox, label will be changed accordingly.
Here is my code.
public event EventHandler _itemChanged;
public MainWindow()
{
List<String> items = new List<string>();
items.Add("C");
items.Add("C++");
items.Add("C#");
items.Add("Java");
items.Add("Js");
InitializeComponent();
combx.ItemsSource = items;
_itemChanged += MainWindow__itemChanged;
DependencyPropertyDescriptor dpcombx;
dpcombx =
DependencyPropertyDescriptor.FromProperty((DependencyProperty)
ComboBox.SelectedValueProperty, typeof(ComboBox));
dpcombx.AddValueChanged(dpcombx, _itemChanged);
}
void MainWindow__itemChanged(object sender, EventArgs e)
{
ComboBox cb = (ComboBox) sender;
lbl_Combx.Content = (string)cb.SelectedItem;
}
The problem is, EventHandler is not getting called. Please help me.
here is the XAML
<Window x:Class="DP.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ComboBox Name="combx"
HorizontalAlignment="Left"
Margin="57,121,0,0"
VerticalAlignment="Top"
Width="120" />
<Label Content=""
x:Name="lbl_Combx"
HorizontalAlignment="Left"
Margin="368,182,0,0"
VerticalAlignment="Top" />
</Grid>
</Window>
You need to pass the dependency object (comboBox) in the AddValueChanged instead of its property descriptor.
dpcombx.AddValueChanged(combx, _itemChanged);

How to diplay/call an UserControl from another UserControl at click both situated in one MainWindow (C#/Xaml)

I'm pretty stuck right now, i'm gonna explain my problem and what i want.
In my solution i have a mainWindow, in that MainWindow i call the first userControl Who is situated in an userControlLibrary. I'ts a menu with button. I want when i click on the first button of the first userControl, i want put the visibility of the second usercontrol to visible (too situated in the userControlLibrary). But i try many things but no one works.
The first userControl is UC_MenuSlider and UC_Start_Study is the second who have to be visibile after click on the button on the first one. At launch UC_Start_Study is hidden.
This is a part of the code of my Mainwindow:
<Grid Name="MainGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<UserControlLibrary:UC_StartStudy x:Name="UC_Start_Study" Grid.Column="1" Height="Auto" Width="Auto" Margin="70 0 0 0" Visibility="Hidden"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.1*" MaxWidth="240" MinWidth="240" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<UserControlLibrary:UC_MenuSlider x:Name="UC_MenuSlider" Grid.Column="0"/>
</Grid>
</Grid>
A part of the code of my first UserControl (UC_MenuSlider):
<Grid Name="Grid_Menu" HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button x:Name="Start_Study" Grid.Row="0" Grid.Column="0" Margin="0" Content="Start Study" FontSize="16" Click="Start_Study_Click">
</Button>
</Grid>
At first a basic event,just an event click in my first userControl. with code behind like that:
public void Start_Study_Click(object sender, RoutedEventArgs e)
{
var startStudy = new UserControlLibrary.UC_StartStudy();
startStudy.Visibility = Visibility.Visible;
}
Don't works. Then i use 'RoutedEvent' But I don't really understand who it works.
I hope my question was enough clear, thanks in advance for your anwsers
The problem is because you are creating a new UC_StartStrudy and set its Visibility to Visible. What you really need is to set Visibility of the one in your XAML: UC_Start_Study
public void Start_Study_Click(object sender, RoutedEventArgs e)
{
UC_Start_Study.Visibility = Visibility.Visible;
}
And you could also use XAML databinding the Visibility property of your UC_StartStrudy, and set its value in your code:
XAML:
<Window.Resourses>
<BooleanToVisibilityConverter x:Key="BooltoVisible" />
</Window.Resourse>
.....
<UserControlLibrary:UC_StartStudy x:Name="UC_Start_Study" Grid.Column="1" Height="Auto" Width="Auto" Margin="70 0 0 0" Visibility="{Binding IsUCStartStudyVisible, Converter={StaticResource BooltoVisible}}"/>
Code (remember to implement INotifyPropertyChanged ):
//implement INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChange(String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
//property for data binding
private bool _isucstartstudyvisible = false;
public bool IsUCStartStudyVisible
{
get{return _isucstartstudyvisible;}
set{_isucstartstudyvisible=value; RaisePropertyChange("IsUCStartStudyVisible");}
}
//your event to change the visibility
public void Start_Study_Click(object sender, RoutedEventArgs e)
{
IsUCStartStudyVisible=true;
}
I don't understand why you are taking a new instance of UC_StartStudy() as you have already added this in your MainWindow.
Can't you simply turn the visibility of UC_Start_Study as visible within the code.
Let me show you how you can do this.
try
public void Start_Study_Click(object sender, RoutedEventArgs e)
{
this.UC_Start_Study.Visibility = Visibility.Visible;
}

Reach a TextBlock from a specific ListViewItem from the ListView in Windows Phone 8.1 XAML programmatically

I am a new developer on Windows Phone 8.1, I am try to reach a specific ListView item from the ListView collection and be able to color it or color the TextBock inside of it, But I can't reach the item or reach any of items inside of ListView, Please take a look for my below code :
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
SQLiteRT db1 = new SQLiteRT();
var db_connection = await db1.Connection("MyDB.sqlite");
List<MyTBL> t_list = db1.GetTable("SELECT * FROM MyTBL LIMIT 4 ORDER BY RANDOM() ;");
db_connection.Close();
LV_Options.ItemsSource = t_list;
}
// my List View called LV_Options
private void LV_Options_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListView lv1 = sender as ListView;
if (lv1 == null)
return;
MyTBL wrd = lv1.SelectedItem as MyTBL;
if (wrd == null)
return;
TextBlock tb = lv1.FindName("TB_AMean1") as TextBlock;
tb.FontSize = 17; // here I got debug error (it not worked !!!!!!!)
var item = LV_Options.Items.ElementAt(3); // this seems not work also !!!!
item.BackColor = Color.LightSteelBlue;
}
As you can see above, I tried to reach a specific item by LV_Options.Items.ElementAt(3) but it doesn't work! I also tried to reach the TextBlock from the selected List view item, but also not worked !
(Updated)
XAML code :
<!-- Title Panel -->
<StackPanel Grid.Row="0" Margin="19,0,0,0">
<TextBlock Name="TB_Rslt" Text="Here result of your answer" Style="{ThemeResource TitleTextBlockStyle}" Margin="0,12,0,0"/>
<TextBlock Text="page title" Margin="0,-6.5,0,26.5" Style="{ThemeResource HeaderTextBlockStyle}" CharacterSpacing="{ThemeResource PivotHeaderItemCharacterSpacing}"/>
</StackPanel>
<!--TODO: Content should be placed within the following grid-->
<Grid Grid.Row="1" x:Name="ContentRoot" Margin="19,10,19,15">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Name="TB_Question" Text="Choose Answer " Margin="0,0,25,0" HorizontalAlignment="Right" FontWeight="Bold" FontSize="22" FontFamily="Verdana" RenderTransformOrigin="0.5,0.5" />
<TextBlock Name="TB_EnWord" Text="" Margin="90,0,15,0" HorizontalAlignment="Left" FontWeight="Bold" FontSize="22" FontFamily="Verdana" RenderTransformOrigin="0.5,0.5" TextAlignment="Right" />
<StackPanel Grid.Row="1" Margin="5,22,0,0">
<ListView Name="LV_Options" SelectionChanged="LV_Options_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Margin="6">
<StackPanel VerticalAlignment="Top" Margin="10,0,0,0">
<TextBlock Name="TB_AMean1" Text="{Binding AMean1}" TextWrapping="Wrap"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
<Button Name="Btn_Answer" Content="Ansewr" HorizontalAlignment="Left" Grid.Row="1" VerticalAlignment="Bottom" Click="Btn_Answer_Click"/>
My application is a quiz application that offer 4 choices/options as answers for each question, and when user select a true answer, I want to highlight the true answer(true choice) by make its background to green, and if the user selected wrong answer/option I want to make the background of that answer (a specific List View item) with red.
Any help please ?
You're not going to be able to access an element inside a data template like that. Instead, leverage the binding to a view model to set the color and other view-related properties. First, create a wrapper view model for your data class:
public class MyTBLViewModel : INotifyPropertyChanged
{
public MyTBL Entity
{
get { return _entity; }
}
private readonly MyTBL _entity;
public Brush Highlight
{
get { return _brush; }
set
{
_brush = value;
RaisePropertyChanged("Highlight");
}
}
private Brush _highlight;
public double ItemFontSize
{
get { return _itemFontSize; }
set
{
_itemFontSize = value;
RaisePropertyChanged("ItemFontSize");
}
}
private Brush _itemFontSize;
public MyTBLViewModel(MyTBL entity)
{
_entity = entity;
_highlight = new SolidColorBrush(Colors.Transparent);
_itemFontSize = 12;
}
public event PropertyChangedEventArgs PropertyChanged;
protected void RaisePropertyChanged(string propName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propName));
}
}
Use this as your ItemsSource:
List<MyTBLViewModel> t_list = db1.GetTable("SELECT * FROM MyTBL LIMIT 4 ORDER BY RANDOM() ;")
.AsEnumerable().Select(entity => new MyTBLViewModel(entity)).ToList();
Now in your view, bind the view elements to "Highlight" and "ItemFontSize", and to any other properties you like:
<ListView.ItemTemplate>
<DataTemplate>
<Grid Margin="6" Background="{Binding Highlight}">
<StackPanel VerticalAlignment="Top" Margin="10,0,0,0">
<TextBlock Name="TB_AMean1" Text="{Binding Entity.AMean1}" TextWrapping="Wrap"
FontSize="{Binding ItemFontSize}"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
Finally, you can get the data item from the SelectionChangedEventArgs -- use it to update your view-related properties:
private void LV_Options_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
foreach (var item in e.AddedItems.OfType<MyTBLViewModel>())
{
item.Highlight = new SolidColorBrush(Color.LightSteelBlue);
item.ItemFontSize = 17;
}
foreach (var item in e.RemovedItems.OfType<MyTBLViewModel>())
{
item.Highlight = new SolidColorBrush(Colors.Transparent);
item.ItemFontSize = 12;
}
}
var item = LV_Options.Items.ElementAt(3);
This line is incorrect. It will not return you a TextBlock. I don't know what a .BackColor is, and it should not compile. The Items property in a ListView will return you a list of ListViewItems. If you want to access the inside element from a ListViewItem, you'll need to access the ContentTemplateRoot property.
Do not use var ever. It lets you assume that you know the type, whereas if you explicitly typed the declaration you would realize you're doing it wrong.
MyTBL wrd = lv1.SelectedItem as MyTBL;
if (wrd == null)
return;
TextBlock tb = lv1.FindName("TB_AMean1") as TextBlock;
What is a MyTBL type? FindName is only available to framework DependencyObjects so I'm assuming it's a user control? You have to provide a lot more code to show us what you're doing and what you're setting the ListView's ItemsSource and ItemTemplate with and what these errors are and how you have 2 breaking debug errors at once and what the error messages are.
Comprehending runtime error messages is a huge part of being a good developer.

DependencyProperty binding error, programmatically

What I have is a well-working C# and XAML code, which does exactly what it is supposed to do, well, almost exactly. I am trying to make my custom, working, DependencyProperty for UserControl - and it is made, well-formed and supposedly working. There are two properties: SumOfApproximationsProperty and SumOfPositionsProperty. These getters and setters simply do not get invoked on certain actions - and this is my problem. They are declared in this UserControl class:
public partial class PresentationCell : UserControl
{
public Label SumOfApproximations;
public Label SumOfPositions;
public PresentationCell()
{
InitializeComponent();
DataContext = this;
this.MinHeight = 40;
this.MinWidth = 40;
SumOfApproximations = this.SumOfApproximation;
SumOfPositions = this.SumOfPosition;
}
public static readonly DependencyProperty SumOfApproximationsProperty =
DependencyProperty.Register("AproximationsProperty", typeof(String),
typeof(PresentationCell), new UIPropertyMetadata(null));
public static readonly DependencyProperty SumOfPositionsProperty =
DependencyProperty.Register("PositionsProperty", typeof(String),
typeof(PresentationCell), new UIPropertyMetadata(null));
public String AproximationsProperty
{
get { return (String)GetValue(SumOfApproximationsProperty); }
set { SetValue(SumOfApproximationsProperty, value); }
}
public String PositionsProperty
{
get { return (String)GetValue(SumOfPositionsProperty); }
set { SetValue(SumOfPositionsProperty, value); }
}
}
As You can see, it is composed of two Labels, that have their own text-setting properties. And here's this UserControl XAML:
// USER CONTROL XAML
<UserControl x:Class="PodstawyModelowaniaISymulacjiRozmytej.Controls.PresentationCell"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*">
</ColumnDefinition>
<ColumnDefinition Width="2*">
</ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition Height="1*">
</RowDefinition>
<RowDefinition Height="2*">
</RowDefinition>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Label Name="SumOfApproximation" Content="{Binding Path=AproximationsProperty}">
</Label>
</Grid>
<Grid Grid.Row="1">
</Grid>
</Grid>
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="1*">
</RowDefinition>
<RowDefinition Height="2*">
</RowDefinition>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
</Grid>
<Grid Grid.Row="1">
<Label Name="SumOfPosition"></Label>
</Grid>
</Grid>
</Grid>
</UserControl>
This UserControl is going to be used with DataGrid (as it's cells), which is declared below (in XAML):
// MAIN WINDOW DATAGRIG DECLARATION MAINWINDOW.XAML
<Grid Grid.Row="2" Name="DataThree_Grid">
<DataGrid Name="ResultData_DataGrid" HeadersVisibility="Row" Margin="5 5 5 5"></DataGrid>
</Grid>
Here's the code, that prepares and creates a column in this DataGrid, filled with PresentationCell UserControls:
// MAIN WINDOW CREATE COLUMN FOR DATAGRID FUNCTION MAINWINDOW.XAML.CS
private DataGridTemplateColumn CreatePresentationTemplateColumn(Binding positions, Binding aproximations)
{
DataGridTemplateColumn doubleOnlyTextBoxColumn = new DataGridTemplateColumn();
FrameworkElementFactory factory = new FrameworkElementFactory(typeof(PresentationCell));
DataTemplate dataTemplate = new DataTemplate();
factory.SetValue(PresentationCell.SumOfApproximationsProperty, aproximations);
factory.SetValue(PresentationCell.SumOfPositionsProperty, positions);
dataTemplate.VisualTree = factory;
doubleOnlyTextBoxColumn.CellTemplate = dataTemplate;
return doubleOnlyTextBoxColumn;
}
Other code, that can be deemed useful for You to answer this question:
// MAIN WINDOW INITIALIZING BUTTON MAINWINDOW.XAML.CS
private void SubtractionLR_Button_Click(object sender, RoutedEventArgs e)
{
MyData[] table = new MyData[]
{
new MyData
{
Values = new element[2]
{
new element
{
var1 = 7,
var2 = 6
},
new element
{
var1 = 4,
var2 = 1
}
}
},
new MyData
{
Values = new element[2]
{
new element
{
var1 = 67,
var2 = 3
},
new element
{
var1 = 44,
var2 = 1
}
}
}
};
fillPresentationDataGrid(ResultData_DataGrid, table);
}
Now, after all of the code has been described, the problem lingers here. As You can see, I am trying to create Binding object for my column of PresentationCell UserControls. The problem is, that this String in this Binding is rather unknown for me - its specification and so on. As a result, program cannot find data that should be provided to my control (and for its labels) through this binding. The data should come from MyData[] table. Program shows an error about "cannot find Values" etc. and the cells in DataGrid are blank.
// MAIN WINDOW FILLING PRESENTATION GRID FUNCTION MAINWINDOW.XAML.CS
private void fillPresentationDataGrid(DataGrid dataGrid, MyData[] table)
{
dataGrid.AutoGenerateColumns = false;
for (int i = 0; i < table[0].Values.Length; i++)
{
DataGridTemplateColumn col = CreatePresentationTemplateColumn(new Binding("Values[" + i + "].var1"), new Binding("Values[" + i + "].var2"));
dataGrid.Columns.Add(col);
}
dataGrid.ItemsSource = table;
}
EDIT
All I want is to get that MyData[] table content displayed on DataGrid control using my own custom UserControl. When I change that factory.SetValue(PresentationCell.SumOfApproximationsProperty, aproximations); into factory.SetValue(PresentationCell.SumOfApproximationsProperty, "foo");, the DataGrid will display "foo"'s.
EDIT2
Unfortunately, the problem still exists.
In the constructor of PresentationCell you set this.DataContext = this.
By setting DataContext to your control you are breaking the inheritance of this property and thats why setting the bindings in CreatePresentationTemplateColumn wont work.
To fix that you can remove this line and bind the controls by RelativeSource/ElementName or you can set the dataContext to the main grid in PresentationCell instead of the root level

Categories