Diskuze: wpf datagrid
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.


To je problém s datagridem, musíš totiž změnit svůj pohled na datagrid.
Datagrid je kontrolka, která reprezentuje určitá data, která kontrolce binduješ. Což znamená, že mít z kontrolky znova přístup k datům je de facto blbost. Uvědom si, že když DataGridu binduješ určitou kolekci, tak ona ti tu kolekci zobrazí jako tabulku, kde řádky jsou obvykle položky kolekce, jejichž vlastnosti zobrazují sloupce.
A teď - máš-li kolekci dat, kterou předáš datagridu, víš, že někde v té kolekci se nacházejí i data, která se v datagridu zobrazí v buňce, podle které bys chtěl pozadí měnit.
Co z toho plyne? Že data pro barvu pozadí nemáš získat přes datagrid,
ale přímo přes kolekci, kterou datagridu binduješ. Pokud chceš ode mě
napsat nějaký kód, napiš, co je to za data a na základě čeho chceš
pozadí měnit. Napiš mi také XAML, protože mám pocit, že to co chceš
dělat se dá zakomponovat přímo do bindingu
Frantisek Jesatko:19.8.2018 17:27
tady je xaml
<DataGrid x:Name="grd_uni" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" MinWidth="600" Margin="185,48,2,6" AlternatingRowBackground="#FFD6CECE" GridLinesVisibility="Vertical" VerticalGridLinesBrush="#FF534B4B"/>
Data do datagridu dostavam z kodu takto :
var xxx = from z in db.Zasahs
from k in db.Adresars
from u in db.Uzivateles
where z.id_zakaznika == k.ico && z.id_uzivatele == u.Id
orderby z.datum descending
select new { z.id_zasahu, z.datum, k.nazev, z.pro_technika, z.popis_zavady, z.poslan_vykaz, z.fakturovano, z.fakturovany_dily, z.stav, u.prijmeni, z.upraveno, z.sdileno, z.vytvoreno, z.cislo_stroje };
grd_uni.ItemsSource = xxx.ToList();
Kde položka fakturovano je hodnota "Ano-Ne" , fakturovany-dily je take
hodnota "Ano-Ne"
Podle toho bych rád barvil řádky.
Dále potřebuju předat id z Bindingu tedy hodnotu z_idzasahu.
Díky za pomoc
Frantisek Jesatko:19.8.2018 19:01
Je pravda že mam na datagrid z WF jiný pohled. Ve WPF je celý přístup uplně jiný a docela dost s tím zápasím .
krepsy3:19.8.2018 23:56
Jo aha, takže necháváš WPF, ať to dělá samo... Tak to bude stačit udělat si columntemplaty, ve kterých zrealizuješ ty změny pozadí... napiš mi přesně, co chceš, aby ty buňky dělaly
Frantisek Jesatko:20.8.2018 6:10
Vzhledem k tomu , že přecházím z WF tak binding je věc která mi zůstává utajena. A tak nechávám vše co můžu do v cecku . Jinak teda potřebuju aby sloupec fakturováno pokud obsahuje hodnotu NE tak celý rádek barva červená .
Jedna z alternativ je napisat si vlastny behavior k danemu datagridu.
/// <summary>
///
/// </summary>
public class DataGridRowLoadBackgroudBehaviour : Behavior<DataGrid>
{
#region OnAttached
/// <summary>
///
/// </summary>
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.LoadingRow += this.AssociatedObject_LoadingRow;
}
#endregion
#region OnDetaching
/// <summary>
///
/// </summary>
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.LoadingRow -= this.AssociatedObject_LoadingRow;
}
#endregion
#region AssociatedObject_LoadingRow
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void AssociatedObject_LoadingRow(object sender, DataGridRowEventArgs e)
{
-- v e.Row.DataContext je bindovany object
Complaint current = e.Row.DataContext as Complaint;
if (current != null)
{
if (!string.IsNullOrEmpty(current.PriorityType))
{
-- tu sa vyhodnocuje, kedy ma mat row inu farbu.
if (current.PriorityType.ToUpper() == "A")
e.Row.Background = new SolidColorBrush(Colors.Red);
else
e.Row.Background = null;
}
else
e.Row.Background = null;
}
else
e.Row.Background = null;
}
#endregion
}
V XAML pre prislusny DataGrid:
<i:Interaction.Behaviors>
<cUtils:DataGridRowLoadBackgroudBehaviour/>
</i:Interaction.Behaviors>
kde i je z
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
Kod je kopirovany zo Silverlightu, z jedneho mojho projektu. Bude potreba ho prejst, upravit na WPF, ale princip cez behavior je rovnaky.
M.
Matyáš Černohous:20.8.2018 17:07
Něco podobného jsem řešil. Dělám to přesně tak jak psal krepsy3. Do
DataGridu nabinduju kolekci a změnu dat (např. změna barvy pozadí jedné
buňky nebo celého řádku) provádím přes controller. Model implementuje
rozhraní INotifyPropertyChanged, takže kdykoliv změním nějaký item,
který mám v kolekci, tak se změna hned projeví v DataGridu.
Binding je sám o sobě dost užitečná věc, protože vlastně můžeš díky
tomu měnit skoro jakoukoliv vlastnost.
Tady je moje řešení. Je zde binding dat do jednotlivých DataGridTextColumnů. Nevím jak to je přesně, ale vypadá to, že dědí z textBoxu, takže přes setter můžeš upravovat jakoukoli vlastnost jako kdyby si pracoval s TextBoxem - tudíž i barvu pozadí/textu/rámečku... (
<Setter Property="TextBlock.Background" Value="{Binding Color}" />
)
Níže je kód modelu a poté controlleru.
<DataGrid ItemsSource="{Binding}" HorizontalScrollBarVisibility="Hidden" RowHeaderWidth="0" x:Name="data" Background="White" HorizontalAlignment="Stretch"
Margin="1,5" VerticalAlignment="Stretch" BorderBrush="Black" BorderThickness="2,0,2,2" AutoGenerateColumns="False" CanUserResizeRows="False" GridLinesVisibility="All"
ScrollViewer.ScrollChanged="data_ScrollChanged" ScrollViewer.CanContentScroll="True" ColumnHeaderDragCompleted="data_ColumnHeaderDragCompleted"
LayoutUpdated="data_LayoutUpdated" IsReadOnly="True" CanUserReorderColumns="False" CanUserSortColumns="False" UseLayoutRounding="False" IsManipulationEnabled="True"
PreviewMouseWheel="data_PreviewMouseWheel" IsHitTestVisible="False" FontSize="11" FontFamily="Tahoma" >
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<Trigger Property="DataGridCell.IsSelected" Value="True">
<Setter Property="Background" Value="White" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Foreground" Value="Black"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Podsestava}" util:DataGridUtil.Name="ses" ClipboardContentBinding="{x:Null}" Header="Podsestava" FontFamily="Tahoma" FontSize="11" >
<DataGridTextColumn.ElementStyle>
<Style>
<Setter Property="TextBlock.TextWrapping" Value="Wrap" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Pozice}" IsReadOnly="True" util:DataGridUtil.Name="poz" ClipboardContentBinding="{x:Null}" Header="Pozice" FontFamily="Tahoma" FontSize="11">
<DataGridTextColumn.ElementStyle>
<Style>
<Setter Property="TextBlock.TextWrapping" Value="Wrap" />
<Setter Property="TextBlock.Cursor" Value="Hand"></Setter>
<EventSetter Event="TextBlock.MouseDown" Handler="Click" />
<Setter Property="TextBlock.Background" Value="{Binding Color}" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Nazev}" util:DataGridUtil.Name="naz" ClipboardContentBinding="{x:Null}" Header="Název" FontFamily="Tahoma" FontSize="11">
<DataGridTextColumn.ElementStyle>
<Style>
<Setter Property="TextBlock.TextWrapping" Value="Wrap" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Poznamka}" util:DataGridUtil.Name="pozn" ClipboardContentBinding="{x:Null}" Header="Poznámka" FontFamily="Tahoma" FontSize="11">
<DataGridTextColumn.ElementStyle>
<Style>
<Setter Property="TextBlock.TextWrapping" Value="Wrap" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
</DataGrid.Columns>
<DataGrid.ColumnHeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Background" Value="White"/>
<Setter Property="Foreground" Value="Black" />
<Setter Property="Margin" Value="0,0,0,0" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="BorderThickness" Value="0,2,1,2" />
<Setter Property="BorderBrush" Value="Black" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
</DataGrid.ColumnHeaderStyle>
</DataGrid>
Model:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace DokumentacePriprava
{
public class Rozpiska : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public string Podsestava { get; set; }
public string Pozice { get; set; }
public string Nazev { get; set; }
public string Dodavatel { get; set; }
public string Poznamka { get; set; }
private string color;
public string Color
{
get { return color; }
set
{
color = value;
NotifyPropertyChanged();
}
}
public Rozpiska(string podsestava, string pozice, string nazev, string dodavatel, string poznamka)
{
Podsestava = podsestava;
Pozice = pozice;
Nazev = nazev;
Dodavatel = dodavatel;
Poznamka = poznamka;
Color = "Transparent";
}
//tohle je nepodstatný
public string ConvertType(bool en)
{
if (en)
{
if (SettingsHelper.TypeValues.ContainsKey(TypDiluOrig))
return SettingsHelper.TypeValues[TypDiluOrig].Item2;
else
return TypDilu;
}
else
{
if (SettingsHelper.TypeValues.ContainsKey(TypDiluOrig))
return SettingsHelper.TypeValues[TypDiluOrig].Item1;
else
return TypDilu;
}
}
}
}
a controller:
public class RozpiskaController
{
private ObservableCollection<Rozpiska> rozpiska = new ObservableCollection<Rozpiska>();
public RozpiskaController()
{
}
//pridani itemu do kolekce
public void Add(Rozpiska r)
{
rozpiska.Add(r);
}
public ObservableCollection<Rozpiska> GetCollection()
{
return rozpiska;
}
//Změna barvy itemu v kolekci - pokud se item z kolekce rovná itemu u kterého chceš zněnit barvu, tak se provede nastavení barvy z paramentru a ihned se ti projeví změna v DataGridu
public void ChangeColor(Rozpiska r, string hexColor)
{
foreach (var rozp in rozpiska)
{
if (rozp.Equals(r))
{
rozp.Color = hexColor;
break;
}
}
}
}
Vytvoříš si instanci controlleru a přidáš tam itemy. Dále nastavíš u DataGridu ItemSoource na tvoji kolekci a data se zobrazí v DataGridu. Dále pak jen používáš metody z Controlleru. Logiku si doplň podle toho co potřebuješ.
Příklad použití - např po načtení hlavního okna:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
//vytvoreni instance controlleru
RozpiskaController rController = new RozpiskaController();
//pridani itemu do controlleru
rController.Add(new Rozpiska("podst","152","test1","dodavatel","pozn");
rController.Add(new Rozpiska("podst1","2","test2545","dodavatel12","pozn heslo");
rController.Add(new Rozpiska("ledňáček","1982","popart","kofola","nejlepší vzpomínky");
//nastavení ItemSource na kolekci
data.ItemSource = rController.GetCollection();
//Ted by si tam měl mít zobazeny data
//změna barvy políčka pozice, pokud se item v kolekci bude rovnat itemu v parametru
Rozpiska r = new Rozpiska("podst1","2","test2545","dodavatel12","pozn heslo");
rController.ChangeColor(r,"#8ff442"); //Druhý řádek bude mít políčko v řádku pozice obarvený na zeleno
}
Snad ti to pomůže
+20 Zkušeností
+2,50 Kč

Frantisek Jesatko:21.8.2018 19:42
diky za navod je az s podivem jak tak jednoduchou vec jde resit slozite. Tim
nechci narazet na tebe to vubec ale na cely wpf . chapu ze oddelit vzhled od logiky je prehledny ale
vrstva ktera obe veci propoji je mi fakt prozatim utajena .
Bruce:28.8.2018 14:37
Taky by to slo udelat pres DataTriggery asi takto
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding NetworkChecked}" Value="True">
<Setter Property="Background" Value="Green" />
</DataTrigger>
<DataTrigger Binding="{Binding NetworkChecked}" Value="False">
<Setter Property="Background" Value="Orange" />
</DataTrigger>
<DataTrigger Binding="{Binding NetworkDataImported}" Value="False">
<Setter Property="Background" Value="White" />
</DataTrigger>
</Style.Triggers>
</Style>
Frantisek Jesatko:29.8.2018 20:10
Ahoj tak toto řešení je uplně nejlepší jednoduchý jako problém sám díky
Ahoj, rád bych požádal někoho zkušenějšího než jsem já o radu. Zasek jsem se na naprosté banalitě, kterou je načtení konkrétní hodnoty buňky v označeném řádku DataGridu. DataGrid je navázaný na DataTable. Obsahuje i sloupec "Id" jehož hodnotu chci použít pro zobrazení v dalším DataGridu. Děkuji za pomoc.
už jsem zkusil něco jako toto:
private void dataGrid_kategorie_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
DataView DVvybrany = new DataView(sprKonkretni.dtKonkretni);
DataRowView drv = dataGrid_kategorie.SelectedItem as DataRowView ;
string id = drv.Row[0].ToString();
DVvybrany.RowFilter = "Id_Kategorie_tech = id";
dataGrid_konkretni.ItemsSource = DVvybrany;
}
Ale někde je chyba v proměnné "Id" mám sice správnou hodnotu ale do
druhého DataGridu mi to načte jen první dva záznami v pořadí(nezávisle na
řádku který jsem vybral v druhém DataGridu) naopak pokud nahradím proměnou
"Id" za čílici např."2" vše funguje správně .
Ještě jednou děkuji.
Zase jsem se o kousek posunul.
Tak to vypadá že problém mám až při použití "RowFilter".
nefunguje totiž ani toto:
int a = 2;
DVvybrany.RowFilter = "Id_Kategorie_tech = a";
je jasné že to čeká za "=" číslo a ne jen ukazatel(proměnou).
ale jak to obejít sloupec"Id_Kategorie_tech" mám v DB jako int.
Děkuji
Frantisek Jesatko:1.12.2018 23:11
ahoj myslim ze by stacilo toto:
DVvybrany.RowFilter = "Id_Kategorie_tech = ‘a’”;
Karel Labonek:2.12.2018 4:59
Ahoj, děkuji za rychlou reakci na můj dotaz, bohužel to to jsem zkoušel.
s a => Additional information: Sloupec [a] nelze
najít.
s ‘a’ => Additional information: Sloupec [‘a’] nelze
najít.
s [‘a’] => Additional information: Sloupec [‘a’]
nelze najít.
s [a] => Additional information: Sloupec [a] nelze
najít.
Já jsem začátečník tak příliš nevidím pod pokličku některým funkcím, zde se zdá že funkce "RowFilter" v tom mém případě očekává místo "a" číslo. Našel jsem na Netu tuto stránku kde je to shrnuté. DataView RowFilter Syntax [C#]
Zdravím, tak jsem našel řešení. Jak už to v programování bývá řešení bylo zcela banální. Pokud je snad někdo v začátcích s programováním jako já tak by mu to možná mohlo pomoci. Tak problém jsem měl se zadáváním hodnot do "RowFiltr" který se používá pro filtrování instance třídy "DataView" který mi slouží jako "ItemsSource" pro "DataGrid". Nevěděl jsem jak předat hodnoty které budou známi až při běhu App. Např. jak předat hodnotu typu "int" pomocí proměnné.
int a = 2;
DVvybrany.RowFilter = "Id_Kategorie_tech = a"; //Takto to nefunguje !!!
No řešení je vzpomenout si na práci s řetězci string:
int a = 2;
string nazevSloupce = Id_Kategorie_tech;
DVvybrany.RowFilter = string.Format("{0} = '" + a + "'", nazevSloupce);
Zobrazeno 17 zpráv z 17.