MaterialDesignInXAML / MaterialDesignInXamlToolkit

Google's Material Design in XAML & WPF, for C# & VB.Net.
http://materialdesigninxaml.net
MIT License
15.17k stars 3.43k forks source link

Produce demo with FULL catalog [Enhancement] #756

Closed wongjiahau closed 6 years ago

wongjiahau commented 7 years ago
ButchersBoy commented 7 years ago

Hey yes...

I have thought about this, and I think something that could scan ANY XAML library and lists styles and locations of those styles would be useful, and a good start...

wongjiahau commented 7 years ago

To achieve this, I think we can use the XamlWriter class.

image

wongjiahau commented 7 years ago

And also we can load XAML at run time using the code below.

string text = @"<TextBlock Text='test' xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' />";

    // Convert to stream
    // You can also just stream the xaml from a file, using a FileStream
    MemoryStream stream = new MemoryStream(ASCIIEncoding.UTF8.GetBytes(text));

    // Convert to object
    TextBlock block = (TextBlock)System.Windows.Markup.XamlReader.Load(stream);

    //... now you can put that TextBlock somewhere, for example in your main Window

Furthermore, we can use AvalonEdit to highlight the XAML code when displaying them in the demo.

Keboo commented 7 years ago

The big drawback to using the XamlWriter class is that you get the run-time representation of the object. This can get rather large since you can easily end up with a huge amount of XAML that you did not expect. Something simple like this:

<Button Style="{StaticResource MaterialDesignFlatButton}" />

Ends up writing out all of the elements in the style in addition to the button. If someone is expecting to simply Copy and Paste this XAML it could quickly get out of hand.

Since I think the idea result is to display the original logical tree. I am thinking that a solution that parses the BAML and displays that information. Though this is not completely trivial itself. Sure we can go through and load the BAML, but this comes with its own challenges.

Something along the lines of this:

var assembly = Assembly.GetEntryAssembly();
var resourceStream = assembly.GetManifestResourceStream(assembly.GetName().Name + ".g.resources");
if (resourceStream == null) return;
var resourceReader = new ResourceReader(resourceStream);
foreach (var dictionaryEntry in resourceReader.OfType<DictionaryEntry>()
    .Where(de => de.Key is string name &&
                    name.EndsWith(".baml", StringComparison.InvariantCultureIgnoreCase) && de.Value is Stream))
{
    Baml2006Reader reader = new Baml2006Reader((Stream)dictionaryEntry.Value);
    while (reader.Read())
    {
        //TODO?
    }
}

Loading Xaml from the currently executing assembly can have problems since it will load it into the running application. Loading the Xaml this way it will try to load into the running application which causes error due to duplication. This also does not fully solve the problem of linking the UI element back to its corresponding Xaml, but that seems like something that should be solvable.

As an alternative we could attempt to process the Baml as part of the compile process. I have some experience building Fody weavers. This would be similar to how GitLink works. I would envision doing something like:

  1. Iterate over all of the Baml resources in the assembly
  2. Convert the Baml to Xaml (we can do it here since the baml is not part of the running application)
  3. For each element add an attached property that contains a unique id. Save the elements Xaml as an xaml resource.
  4. Save the modified Xaml as Baml as replace the original in the assembly (never done this but I suspect it should be simple-ish). I am also not sure if the new VS Xaml tools will play nice with this or not.
  5. Now given any element in our demo allocation we can simply check it for the attached property. If it exists we can use the unique id on it to look up the xaml resource to display.

Thoughts?

The other question is how to surface this in the demo application. I do like the idea of using the AvalonEdit control to get nice syntax highlighting, though I am not sure how/where that should be displayed in the UI.

wongjiahau commented 7 years ago

@Keboo Yes, that is a big drawback, so currently, I am thinking of doing it the other way round. That is to write the XAML code in CS, then load it into the UI using XamlReader. I'll show it to you the demo soon.

ButchersBoy commented 7 years ago

Hi guys,

Another thought, just parsing the XAML outside of the demo, and spitting out some HTML is worth considering, bedside then we can just add a list to the wiki/website somewhere.

Let's not forget that XAML is just XML so possibly just xpath or linq2xml would get that done.

wongjiahau commented 7 years ago

Second attempt to solve this problem :

Output

image

Xaml Code

image

Code behind

image

How to do it ?

  1. If you want to display the Xaml of a control, just embed it within the XamlDisplayer (make sure the XamlDisplayer is given a name(any name will do)).
  2. Load the Xaml file in the code behind, then call the XamlDisplayer.DisplayXamlCode method.
  3. That's all.

Advantage

  1. This method can be surfaced easily in the MainDemo.wpf without modifying much base code.

Issues

  1. How are we going to load the xaml file? Perhaps using GitLink as suggested by @Keboo

Thank you for reading this. I hope you'll review it.

Please refer to this repository for the full code.

Keboo commented 7 years ago

Hi @wongjiahau this looks very interesting. When I have a little more time I will look over it more closely.

wongjiahau commented 7 years ago

Third attempt to solve this problem :

Output

demo

Xaml Code

image

Code behind

image

How to do it ? (Now it's even easier!)

  1. Just embed the controls that you want its XAML to be displayed within a single XamlDisplayerPanel (remember to name the XamlDisplayerPanel).
  2. Load the Xaml file from Github in the code behind, then call the XamlDisplayerPanel.Initialize method.
  3. That's all.

Advantage

  1. This method can be surfaced easily in the MainDemo.wpf without modifying much base code.

Thank you for reading this. I hope you'll review it. Please refer to this repository for the full code of XamlDisplayerPanel.

Keboo commented 7 years ago

Hi @wongjiahau I am trying to run the code, but it appears that one of the references in CodeDisplayer is a local file.

<Reference Include="XamlStyler.Core">
  <HintPath>..\..\..\XamlStyler\XamlStyler.Core\bin\Release\XamlStyler.Core.dll</HintPath>
</Reference>

Is this something that can be checked in?

wongjiahau commented 7 years ago

@Keboo Sorry for the problem, I had already fixed that by including the .dll in the repository in the following directory :

Displaying-XAML/WpfApplication1/CodeDisplayer/DependencyPackage/XamlStyler.Core.dll

There are still problem apparently because XamlStyler.Core.dll is referencing another 2 dlls, I'm triyng to fix this problem by using Costura.Fody [FIXED]

AmitBhatnagar24 commented 7 years ago

I just tried this out, (via download link in gitter) and it is awesome.

This makes the demo app 100x more useful and saves me loads of time.

Great work!

wongjiahau commented 7 years ago

@AmitBhatnagar24 Thanks :) @ButchersBoy I hope you will include this feature in the next release, as this will greatly reduces the gulf of execution. Most of the users (for example myself), whenever I want to use a type of control, I can picture it in my mind, but I can't really remember its code, therefore I'll need the catalog to easily get the code I want.

varunvasisht84 commented 7 years ago

Hello @wongjiahau , Cool stuff. I'll try it with one of my application written in wpf.

varun

AmitBhatnagar24 commented 7 years ago

@wongjiahau This doesn't seem to work anymore - crashes upon launch. I'm suspecting its failing when trying to pull the latest demo code source from GitHub?

wongjiahau commented 7 years ago

@AmitBhatnagar24 Sorry for the inconvenience causes, because I've updated the source code yesterday, try download the latest version here

Keboo commented 6 years ago

This has been implemented in the demo app.