Discussion:
Controls durchlaufen in WPF
(zu alt für eine Antwort)
Alexander Billner
2009-02-03 21:08:57 UTC
Permalink
Hallo zusammen,

ich möchte für alle Controls einer WPF-Page Eigenschaften setzen, z.B. die
Hintergrundfarbe. Ich beschäftige mich erst seit kurzem mit WPF und mache
das bis jetzt so:

In theButton_Click:

[...]
DependencyObject window = LogicalTreeHelper.GetParent(sender as
FrameworkElement);

foreach(DependencyObject obj in LogicalTreeHelper.GetChildren(window as
FrameworkElement))
{
if (Object.ReferenceEquals(obj.GetType(),theButton.GetType()))
{
Button theButton2 = obj as Button;
theButton2.Background = Brushes.Red;
}
}
[...]

Geht das schneller und besser?

Danke und viele Grüße,
Alex
Elmar Boye
2009-02-04 08:15:57 UTC
Permalink
Hallo Alexander,
Post by Alexander Billner
Hallo zusammen,
ich möchte für alle Controls einer WPF-Page Eigenschaften setzen,
z.B. die Hintergrundfarbe.
Um Elemente zu verändern, solltest Du weniger Code schreiben,
als die Möglichkeiten von WPF nutzen.
Um Eigenschaften anzupassen, ohne im einzelnen jedes Element
anzusprechen, bieten sich Ressourcen an:
<URL:http://msdn.microsoft.com/de-de/library/ms742538.aspx>
"Ressourcen (WPF)"

Und das kann über Styles und Trigger bis zum Exzeß ausgebaut
werden, ohne nur eine Zeile Code zu schreiben.

Schau Dir mal die Artikelserien auf Codeproject von Josh Smith
http://www.codeproject.com/KB/WPF/GuidedTourWPF_1.aspx
und Sacha Barber
<URL:http://www.codeproject.com/KB/WPF/BeginWPF1.aspx>

Ein kleines Beispiel für den Hintergrund:

<!-- XAML: -->
<Window x:Class="Wpf1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Button Ressourcen" Height="300" Width="300">
<Window.Resources>
<SolidColorBrush x:Key="ButtonBackgroundBrush" Color="LightBlue"/>
</Window.Resources>
<StackPanel>
<!-- Statisch -->
<Button Background="{StaticResource ButtonBackgroundBrush}"
Content="Statische Farbe"/>
<!--Ändert sich mit Änderung der Ressource -->
<Button Background="{DynamicResource ButtonBackgroundBrush}"
Content="Dynamische Farbe" />
<!-- Systemfarbe -->
<Button Background="{DynamicResource {x:Static SystemColors.DesktopBrushKey}}"
Content="Windows Farbe" />

<Button x:Name="ChangeColorButton"
Margin="0,16"
Content="Farbe Ändern" Click="ChangeColorButton_Click"/>
</StackPanel>
</Window>

<!-- Code-Behind: -->
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}

private void ChangeColorButton_Click(object sender, RoutedEventArgs e)
{
this.Resources["ButtonBackgroundBrush"] = new SolidColorBrush(Colors.Red);

}
}
Frank Dzaebel
2009-02-04 09:56:05 UTC
Permalink
Hallo Alexander,
Post by Alexander Billner
ich möchte für alle Controls einer WPF-Page Eigenschaften
setzen, z.B. die Hintergrundfarbe. Ich beschäftige mich erst
[..] Geht das schneller und besser?
Ja. Im Prinzip vererben sich die Eigenschaften des
Parent (Controls) auf die Childs. Also wäre theoretisch
nur die Background-DP zu setzen:

<Window x:Class="MeinNamespace.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="315" Width="545"
Background="Blue">
[...]

Nun ist es aber so, dass bestimmte Controls wie
ListBox und Button, etc. nicht diese Hintergrund-Farbe
erben, was ganz dezidierte Gründe hat. Etwa die ListBox
muss bei Selection eigene Farben verwenden.

Da Du nun *alle* Controls eigentlich mit
gleichem/ähnlichen Hintergrund haben willst,
muss ich zunächst sagen, das wäre nicht so
besondern ratsam von Stil her. Aber Du kannst
natürlich trotzdem ähnliche Farben wählen.
Wenn, dann aber etwa so:

<Window.Resources>
<Style x:Key="{x:Type TextBox}" TargetType="{x:Type TextBoxBase}">
<Setter Property="Background" Value="LightBlue"/>
</Style>
<Style x:Key="{x:Type ComboBox}" TargetType="{x:Type ComboBox}">
<Setter Property="Background" Value="LightBlue"/>
</Style>
<Style x:Key="{x:Type Button}" TargetType="{x:Type Button}">
<Setter Property="Background" Value="LightBlue"/>
</Style>
</Window.Resources>

[Beispiele für ControlTemplates]
http://msdn.microsoft.com/de-de/library/aa970773.aspx

Also für die Controls, deren DP hier nicht vererbt wird,
gesondert generisch mit einem Style versehen.
Wenn das für alle Windows gelten soll, nutze ggf.:

[Application.Resources-Eigenschaft (System.Windows)
http://msdn.microsoft.com/de-de/library/system.windows.application.resources.aspx

Du brauchst dann eben *nicht* - wie in Elmars Beispiel -
jedem Button einzeln noch die statische Ressource
zuzuweisen.


ciao Frank
--
Dipl. Inf. Frank Dzaebel [MCP, MVP C#]
http://Dzaebel.NET
Alexander Billner
2009-02-04 17:12:56 UTC
Permalink
Post by Frank Dzaebel
Da Du nun *alle* Controls eigentlich mit
gleichem/ähnlichen Hintergrund haben willst,
muss ich zunächst sagen, das wäre nicht so
besondern ratsam von Stil her. Aber Du kannst
natürlich trotzdem ähnliche Farben wählen.
Vielen Dank für Deine und Elmars Ansätze, bringen mich schon mal weiter.
Die Hintergrundfarbe war nur ein Beispiel: ich möchte evtl. in meiner Page
alle Buttons bis auf einen deaktivieren. Und ich habe fünf Stück.
Dann geht das mit Styles nicht mehr, oder??

Viele Grüße,
Alex
Elmar Boye
2009-02-04 17:22:57 UTC
Permalink
Hallo Alexander,
Post by Alexander Billner
Die Hintergrundfarbe war nur ein Beispiel: ich möchte evtl. in meiner Page
alle Buttons bis auf einen deaktivieren. Und ich habe fünf Stück.
Dann geht das mit Styles nicht mehr, oder??
Dafür gibt es in WPF das Konzept eines RoutedCommand, den man über
ein CommandBinding zuweisen kann. Ein kurzes Beispiel zeigt:
<URL:http://msdn.microsoft.com/de-de/library/ms753200.aspx>

Fürs Gesamtverständnis solltest Du studieren:
<URL:http://msdn.microsoft.com/de-de/library/ms752308.aspx>
"Befehlsübersicht"

Gruß Elmar
Frank Dzaebel
2009-02-04 19:48:26 UTC
Permalink
Hallo Alexander,
Post by Alexander Billner
Die Hintergrundfarbe war nur ein Beispiel: ich möchte evtl.
in meiner Page alle Buttons bis auf einen deaktivieren.
Und ich habe fünf Stück.
Alle Controls deaktivieren würde man zum Beispiel
wieder über die Vererbung machen, etwa:

((FrameworkElement)button1.Parent).IsEnabled = false;

Auch hört sich Dein Ansinnen etwas nach
RadioButton-Funktionalität an, wo WPF (auch
Windows Forms) ja schon automatisch erkennt, dass die
anderen nun unchecked dargestellt werden sollen.

Es gibt nun einige Möglichkeiten, Dein Vorhaben
zu lösen. Um zu wissen, welche man wählt, wäre
zum Beispiel wichtig, welche wie generisch das
ganze sein soll - also haben die Buttons vielleicht
immer ein "x" im Namen, geht es um alle Windows,
oder nur in einem Window. Es ist oft sinnvoll, dass
man die Bindung an die Gruppe über den Designer
angeben kann. Ist es richtig, dass das auch Dein
Ansinnen ist? Dann würde man zum Beispiel die
Buttons in einen Canvas (o.ä.) tun und dann etwas wie:

canvas1.IsEnabled = false;

machen. Selbst, wenn nun aber die Buttons nicht alle
direkt in den visuellen Container passen, kannst Du
durchaus (zum Beispiel einen) mittleren Button über
die Cursor-Tasten logisch ausserhalb des Containers
und visuell innerhalb setzen.
_______

Nun gäbe es aber auch die Möglichkeit, dass Du
das auch nicht möchtest. Dann kann man zum Beispiel
eine vorhanden Eigenschaft wie "Tag" benutzen, in Dein
gewünschten "Button.Tag" im Designer ne 1 (o.ä.)
schreiben. Dann zum Beispiel:

foreach (UIElement el in canvas1.Children)
if (elem is Button) el.IsEnabled = (((Button)el).Tag != null);

_______

Auch über die Command-Eigenschaft, die der Button über die
ICommandSource-Schnittstelle implmentiert, gibt es Möglichkeien.
Hier eine zentrale Einstiegsseite mit Beispielen:

[Übersicht über die Eingabe]
http://msdn.microsoft.com/de-de/library/ms754010.aspx#commands
(und darunter links in der Inhaltsangabe weitere)

[ButtonBase.Command-Eigenschaft (System.Windows.Controls.Primitives)]
http://msdn.microsoft.com/de-de/library/system.windows.controls.primitives.buttonbase.command.aspx

________

Ist Dein Ansinnen noch generischer und Deine Funktionalität
nicht nur auf so einfache Dinge, wie IsEnabled beschränkt,
gibt es auch Konstruktionen über objektorientierte Klassen mit
eigenen Steuerelementen. Aber da warte ich einfache mal
Deine Antwort ab. Da Du ja erst noch am Anfang stehst,
sollten die am Beginn genannten Möglichkeiten sicher fürs
erste ausreichen.


ciao Frank
--
Dipl.Inf. Frank Dzaebel [MCP/MVP C#]
http://Dzaebel.NET
Alexander Billner
2009-02-05 05:26:15 UTC
Permalink
Am Wed, 4 Feb 2009 20:48:26 +0100 schrieb Frank Dzaebel:

Vielen Dank noch einmal, Frank, Elmar.
Ich werde mich am Wochenende mit euren Antworten beschäftigen,
mal sehen, was für mich in Frage kommt.

Viele Grüße,
Alex

Loading...